home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 138 / 138.xpi / chrome / stumbleupon.jar / content / stumbleuponOverlay.js < prev    next >
Text File  |  2010-02-03  |  555KB  |  21,604 lines

  1. /***
  2.  
  3. The contents of this file are subject to the Mozilla Public
  4. License Version 1.1 (the "License"); you may not use this file
  5. except in compliance with the License. You may obtain a copy of
  6. the License at http://www.mozilla.org/MPL/
  7.  
  8. Software distributed under the License is distributed on an "AS
  9. IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10. implied. See the License for the specific language governing
  11. rights and limitations under the License.
  12.  
  13. The Original Code is StumbleUpon code.
  14. The Initial Developer of the Original Code is StumbleUpon.
  15.  
  16. Portions created by StumbleUpon are
  17. Copyright (C) 2002-2007 StumbleUpon.  All
  18. Rights Reserved.
  19.  
  20. Original Author: Geoff Smith <geoff@stumbleupon.com>
  21. Contributor(s): Garrett Camp <gmc@stumbleupon.com>
  22.         Joe Walp <joewalp@yahoo.com>
  23.         Manpreet Singh (loonyone.stumbleupon.com)
  24.  
  25. Questions/Comments?  Please send them here:
  26.  
  27. http://www.stumbleupon.com/feedback.php
  28.  
  29. Copyright notes:
  30. 1. No code contributed by Manpreet Singh remains in the codebase.
  31. 2. Regardless of intellectual property claims, Manpreet Singh supports
  32.    changing the license from MPL to MPL/GPL/LGPL tri-license if other
  33.      contributors so choose.  For reference:
  34.      http://www.mozilla.org/MPL/boilerplate-1.1/mpl-tri-license-txt
  35. 3. For additional intellectual property considerations, search for 
  36.    [IP:] and [kudos:] in the code.
  37.  
  38. ***/
  39.  
  40. //************** GLOBALS ****************/
  41. var su_private_label = "2010020301";
  42. var su_source_label = "AM";
  43. var su_log_communication = true;
  44. var su_log_sync = false;
  45. var su_log_polling = false;
  46. var su_log_resource_cfd = false;
  47. var su_log_mimetype = false;
  48. var su_force_migrate_prerelease = ((su_private_label.indexOf("ALPHA") == 0) || (su_private_label.indexOf("BETA") == 0));
  49. var su_test_stumblethru_update = false;
  50. var su_test_info = false;
  51. var su_test_extra_init = false;
  52. var su_test_campus_dist = false;
  53. var su_test_facebookhome_prompt = false;
  54. var su_test_searchpage_prompt = false;
  55. var su_test_mimetype = false;
  56. var su_disable_sync = false;
  57. var su_enable_freereporting = true;
  58. var su_enable_message_log = (su_private_label.indexOf("ALPHA") == 0);
  59.  
  60. var mozbar_version = "3.63";
  61. var su_servername = 'stumbleupon.com';
  62. var su_serverhttp = 'http://www.' + su_servername + '/';
  63. var su_serverhttps = 'https://www.' + su_servername + '/';
  64. var su_base_url = su_serverhttp;
  65. var su_ds = null;
  66. var su_host = null;
  67. var su_stumbleReporter = null;
  68. var su_window_time_ms = (new Date()).getTime();
  69. var stumbleid = 0;
  70. var stumblepass = "";
  71. var su_visited_login_page = false;
  72. var su_promo_mode = false;
  73. var su_login_initialized = false;
  74. var su_stumble_throttled = false;
  75. var su_info_spec = null;
  76. var su_tag_instructions = "Search or Tag here";
  77. var su_tagged_folder_name = "Unfiled/Tagged";
  78. var su_video_tagid = 1196;
  79. var su_enable_hashed_password;
  80. var su_prev_nick = null;
  81. var su_random_delay = 0;
  82. var su_cacheTimer = 0;
  83. var su_prefetcher;
  84. var su_last_typed_tag = 0;  // timestamp of the last time you typed a new tag
  85. var su_old_search = ""; // the search you had before we change due to tagging
  86. var su_url_has_tag = false;
  87. var su_search_service_id = null;
  88. var su_drawer_timers = new Object();
  89.  
  90. var su_visited_searchbox = 0;
  91. var su_toggling_toolbar = false;
  92. var su_moving_toolbar = false;
  93. //var su_check_referral_flag = 0;
  94. var su_check_referral_timer = null;
  95. var su_process_rarely_timer = null;
  96. var su_dist_time_timer = null;
  97. var su_toolbar_disabled = false;
  98.  
  99. var su_quote = "";
  100. var su_photoblogimage = null;
  101.  
  102. var su_ratings = new Object(); // array of url->su_ratings 
  103. var su_tag_lists_by_url = new Object(); // object url->tag_list
  104. var su_tags = new Array(); // array of objects with properties 'url' and 'tag_list'
  105.  
  106. var su_selected_category = "0";
  107. var su_stumble_async_context = null;
  108. var su_stumblevideo_toolbar_rate = false;
  109. var su_pending_stumblevideo_stumble = false;
  110. var su_pending_stumblevideo_rate_context = null;
  111. var stumbled_url = ""; // your last stumble
  112. var su_redirect_url = "";
  113. var stumbled_redirect; // the url your last stumble got redirected to
  114. var su_previous_query_category = "";
  115. var su_stumble_action_count = 0;
  116. var stumbles; // queue of urls to be stumbled upon in the future
  117. var su_user_interests = new Array(); // array of intersts the user is signed up for
  118. var su_catnames = new Array(); // array of catid -> catname (topics.csv)
  119. var su_catids = new Object(); // array of catid -> catname (topics.csv)
  120. var su_foldernames = new Array(); // folder names
  121. var su_topicfolders = new Array(); // maps topic id's to su_foldernames
  122. var su_queries; // list of last 100 queries
  123.  
  124. var su_notifier_dialog = null;
  125. var su_preference_dialog = null;
  126. var su_customize_invoked_from_preference_dialog = false;
  127. var su_uninstall_scheduled = false;
  128. var su_remove_data_scheduled = false;
  129.  
  130. // The following are used by the keybinding routines, and some are
  131. // accessed by the preferenceDialog and by the keybinding migration
  132. // routine.
  133. var su_keys_by_keyspec = new Object();
  134. var su_commands_by_keyspec;
  135. var su_removed_keybindings_by_keyspec = new Object();
  136. var su_keyids_by_eventkeycode = new Object();
  137. var su_chars_by_keyid = new Object();
  138. var su_keyids_by_char = new Object();
  139. var su_recent_keypress_modifiers;
  140. var su_load_image_count = 0;
  141. var su_has_searchbox = false; // for efficiency
  142. var su_keep_searchbox_focus = false;
  143. var su_searchbox_was_focused = false; // used by the searchbox click kludge
  144. var su_gui_initialized = false;
  145.  
  146. var su_searchlinks_dialog_detail = null;
  147.  
  148. // The following are used by the toolbar location and overflow routines.
  149. var su_sidebar_was_hidden;
  150. var su_old_toolbar_x;
  151. var su_old_toolbar_position = null;
  152. var su_old_toolbar_position_group = null;
  153. var su_reflow_delayed = false;
  154. var su_overflow_popup_open = false;
  155. var su_referred_popup_open = false;
  156. var su_moving_splitter = false;
  157. var su_toolbar_justification;
  158. var su_bookmarks_sibling_loc = null;
  159. var su_persist_queue = new Array();
  160.  
  161. var su_resize_window_width = 0;
  162. var su_resize_window_dirty = false;
  163.  
  164. var su_referral_menu_dirty = true;
  165. var su_referral_popup_open = false;
  166. var su_refreshing_referral_menu = false;
  167.  
  168. var su_dyn_channels_dirty = true;
  169. var su_mode_more_popup_open = false;
  170. var su_refreshing_dyn_channels = false;
  171.  
  172. var su_pagemeta_dirty = true;
  173. var su_refreshing_pagemeta = false;
  174.  
  175. var su_refreshing_category_selector = false;
  176. var su_blocked_category_selector_refresh_pending = false;
  177.  
  178. var su_new_install = false; // true for first run after install
  179. var su_new_upgrade = false; // true for first run after upgrade
  180. var su_new_user = false;    // true between getid.php and interests_after.php
  181. var su_prev_version;        // set when su_new_upgrade is true
  182. var su_migrate_toolbar_position_scheduled = false;
  183.  
  184. var su_d_rec_rating = false;
  185.  
  186. // Handle StumbleUpon sidebar (conversation bar)
  187. var su_sidebar_enabled = false; // Disabled by default
  188.  
  189. //************** END GLOBALS ****************/
  190.  
  191. //********* INCLUDES *****************//
  192. function su_include(uri)
  193. {
  194.     try {
  195.         su_get_service(
  196.                     "@mozilla.org/moz/jssubscript-loader;1",
  197.                     "mozIJSSubScriptLoader")
  198.                     .loadSubScript(uri);
  199.     }
  200.     catch (e) {
  201.         if ((uri != "chrome://stumbleupon/content/extra.js") || 
  202.                     su_test_extra_init)
  203.             su_log_error("INCLUDE", e, uri);
  204.     }
  205. }
  206.  
  207. var su_toolbar_api = {
  208.     processCommands: function(commands) {
  209.         su_process_commands(commands);
  210.     }
  211. }
  212.  
  213. su_include("chrome://stumbleupon/content/migrate.js");
  214. su_include("chrome://stumbleupon/content/prefetcher.js");
  215.  
  216. //********* END INCLUDES *****************//
  217.  
  218.  
  219. //********* INITIALIZATION *****************//
  220. // See also the bottom of the file for additional initialization.
  221.  
  222. function su_load_categories()
  223. {
  224.     su_catnames = su_ds.getDictionary("catid:topic_name");
  225.     su_catids = su_ds.getDictionary("topic_name:catid");
  226.     su_topicfolders = su_ds.getDictionary("catid:folder_name");
  227.     su_foldernames = su_ds.getAlphaSupertopicNames();
  228.     
  229.     // Load topics.csv
  230.  
  231.     // okay, let's try topics.csv that came with the xpi
  232. //!!! bah, let's not bother updating topics.csv over the net
  233. // it changes so infrequently
  234.  
  235. /*
  236.     alert(catdat);
  237.  
  238. //!!!     var catdat = su_read_file_global("topics.csv");
  239.  
  240.     var da = new Date();
  241.     var timenow = da.getTime();
  242.     var oneweek = 24 * 60 * 60 * 7 * 1000; // javascript stores time in milliseconds
  243.  
  244.     var last_categories = su_ds.getValue("$categories_dat");
  245.     if (catdat == "" || timenow - last_categories > oneweek)
  246.     {
  247.         // We need to hit the server and grab topics.csv
  248.         //!!! mozilla's caching is on crack (it doesn't even check server to see if there's a new vesrion unless we create a salt!)
  249.         var res = su_post_url_server("topics.csv", null);
  250.     
  251.         // If we got it, make it catdat and write it to disk
  252.         if (res.status == 200)
  253.         {
  254.              catdat = res.response;
  255. //!!!            su_write_file_global("topics.csv", catdat);
  256.         }
  257.  
  258.         // Write last_categories
  259.         last_categories = timenow;
  260.         su_ds.setValue("$categories_dat", timenow);
  261.         su_ds.flushPrefs();
  262.     }
  263.  
  264. */
  265. }
  266.  
  267.  
  268. function su_is_server_page(url, path)
  269. {
  270.     return ((url.indexOf(su_serverhttp + path) == 0) ||
  271.             (url.indexOf(su_serverhttps + path) == 0));
  272. }
  273.  
  274. function su_process_slclicks(force)
  275. {
  276.     if (su_ds.getValue("#slprocessed") && (! force))
  277.         return;
  278.     su_ds.setValue("#slprocessed", true);
  279.     var slclicks = su_ds.selectAllRows("slclick");
  280.     var slstats = su_ds.getValue("$slstats").split(":");
  281.     var profile = new Object();
  282.     var url_page1 = new Object();
  283.     var url_page2 = new Object();
  284.     var tag_page = new Object();
  285.     var result = new Object();
  286.     var result_dt = new Object();
  287.     var result_dc = new Object();
  288.     var result_ds = new Object();
  289.     var result_dl = new Object();
  290.     var result_df = new Object();
  291.     var result_dm = new Object();
  292.     var result_dz = new Object();
  293.     var index_clicked = new Array();
  294.     var index_friend_clicked = new Array();
  295.     var i;
  296.     for (i = 0; i < 10; i++)
  297.     {
  298.         index_clicked[i] = 0;
  299.         index_friend_clicked[i] = 0;
  300.     }
  301.     
  302. // fields
  303. // ---------------
  304. // userid
  305. // timestamp
  306. // session query num
  307. // query term count
  308. // result count
  309. // decorated count
  310. // friend decorated count
  311. // first decorated num
  312. // url_page1        clicked count
  313. // comment          clicked count
  314. // url_page2        clicked count
  315. // topic            clicked count
  316. // result           clicked count
  317. // thumbed result           clicked count (dt)
  318. // nickname result          clicked count (df)
  319. // multinickname result     clicked count (dm)
  320. // comment result           clicked count (dc)
  321. // comment level > 0 result clicked count (dl)
  322. // starred > 1 result       clicked count (ds)
  323. // topic result             clicked count (dz)
  324.     
  325.     var slq;
  326.     for (i = 0; i < slclicks.length; i++)
  327.     {
  328.         var row = slclicks[i];
  329.         
  330.         slq = row.q;
  331.         
  332.         if (row.i < 10)
  333.         {
  334.             if (row.r && row.df)
  335.                 index_friend_clicked[row.i]++;
  336.             else if (row.r)
  337.                 index_clicked[row.i]++;
  338.         }
  339.         
  340.         if (row.u)
  341.             url_page1[slq] = (url_page1[slq]) ? (url_page1[slq] + 1) : 1;
  342.  
  343.         if (row.p)
  344.             profile[slq] = (profile[slq]) ? (profile[slq] + 1) : 1;
  345.         
  346.         if (row.n)
  347.             url_page2[slq] = (url_page2[slq]) ? (url_page2[slq] + 1) : 1;
  348.         
  349.         if (row.z)
  350.             tag_page[slq] = (tag_page[slq]) ? (tag_page[slq] + 1) : 1;
  351.         
  352.         if (row.r)
  353.             result[slq] = (result[slq]) ? (result[slq] + 1) : 1;
  354.         
  355.         if (row.r && row.dt)
  356.             result_dt[slq] = (result_dt[slq]) ? (result_dt[slq] + 1) : 1;
  357.         
  358.         if (row.r && row.dc)
  359.             result_dc[slq] = (result_dc[slq]) ? (result_dc[slq] + 1) : 1;
  360.  
  361.         if (row.r && (row.ds > 1))
  362.             result_ds[slq] = (result_ds[slq]) ? (result_ds[slq] + 1) : 1;
  363.  
  364.         if (row.r && row.dl)
  365.             result_dl[slq] = (result_dl[slq]) ? (result_dl[slq] + 1) : 1;
  366.  
  367.         if (row.r && row.df)
  368.             result_df[slq] = (result_df[slq]) ? (result_df[slq] + 1) : 1;
  369.  
  370.         if (row.r && (row.df > 1))
  371.             result_dm[slq] = (result_dm[slq]) ? (result_dm[slq] + 1) : 1;
  372.  
  373.         if (row.r && row.dz)
  374.             result_dz[slq] = (result_dz[slq]) ? (result_dz[slq] + 1) : 1;
  375.     }
  376.     
  377.     var stats = "";
  378.     for (i = 0; i < slstats.length; i++)
  379.     {
  380.         if (slstats[i] == "")
  381.             continue;
  382.         
  383.         slq = slstats[i].split("\t")[1];
  384.  
  385.         if (! url_page1[slq])
  386.             url_page1[slq] = 0;
  387.         
  388.         if (! profile[slq])
  389.             profile[slq] = 0;
  390.         
  391.         if (! url_page2[slq])
  392.             url_page2[slq] = 0;
  393.         
  394.         if (! tag_page[slq])
  395.             tag_page[slq] = 0;
  396.         
  397.         if (! result[slq])
  398.             result[slq] = 0;
  399.         
  400.         if (! result_dt[slq])
  401.             result_dt[slq] = 0;
  402.         
  403.         if (! result_dc[slq])
  404.             result_dc[slq] = 0;
  405.  
  406.         if (! result_ds[slq])
  407.             result_ds[slq] = 0;
  408.  
  409.         if (! result_dl[slq])
  410.             result_dl[slq] = 0;
  411.  
  412.         if (! result_df[slq])
  413.             result_df[slq] = 0;
  414.  
  415.         if (! result_dm[slq])
  416.             result_dm[slq] = 0;
  417.  
  418.         if (! result_dz[slq])
  419.             result_dz[slq] = 0;
  420.  
  421.         stats += stumbleid + "\t" + slstats[i] + "\t" + 
  422.                     url_page1[slq] + "\t" + profile[slq] + "\t" + 
  423.                     url_page2[slq] + "\t" + tag_page[slq] + "\t" + 
  424.                     result[slq] + "\t" + result_dt[slq] + "\t" + 
  425.                     result_df[slq] + "\t" + result_dm[slq] + "\t" + 
  426.                     result_dc[slq] + "\t" + result_dl[slq] + "\t" + 
  427.                     result_ds[slq] + "\t" + result_dz[slq] + "\n";
  428.                     
  429.     }
  430.     
  431.     var istats = "";
  432.     var slistats = su_ds.getValue("$slistats").split(":");
  433.     var slidfstats = su_ds.getValue("$slidfstats").split(":");
  434.     for (i = 0; i < 10; i++)
  435.     {
  436.         istats += (i + 1) + "\t" + slistats[i] + "\t" + 
  437.                     slidfstats[i] + "\t" + index_clicked[i] + "\t" +
  438.                     index_friend_clicked[i] + "\n"
  439.     }
  440.     
  441.     if (stats == "")
  442.         return;
  443.     
  444.     su_ds.globals.sls = new Array();
  445.     su_ds.globals.sluqh = new Object();
  446.     su_ds.globals.sltih = new Object();
  447.     su_ds.setValue("$slstats", "");
  448.     su_ds.setValue("$slistats", "0:0:0:0:0:0:0:0:0:0");
  449.     su_ds.setValue("$slidfstats", "0:0:0:0:0:0:0:0:0:0");
  450.     su_ds.deleteAllRows("slclick");
  451.     su_ds.flushPrefs();
  452.     
  453.     var params = "";
  454.     params = su_arp(params, "slstats", stats);
  455.     params = su_arp(params, "slindexstats", istats);
  456.     params = su_arp(params, "f", su_ds.getValue("$form"));
  457.     
  458.     var context = new Object();
  459.     context.quiet = true;
  460.     su_post_url_server_async(
  461.                 "slstats.php",
  462.                 params,
  463.                 15000,
  464.                 su_generic_done,
  465.                 context);
  466. }
  467.  
  468. function su_get_random_int(min, max)
  469. {
  470.     return Math.floor(Math.random() * (max - min + 1)) + min;
  471. }
  472.  
  473. // initializes user-specific configuration that doesn't involve gui
  474. // elements
  475. function su_load_data1(new_profile)
  476. {
  477.     //!!! We can migrate from flat files to mozStorage after that
  478.     // feature is mature.  We ought to be able to get rid of the
  479.     // length limits on these data stores for clients that include
  480.     // the embedded database.  -- JW
  481.  
  482.     stumbled_url = "";
  483.     su_redirect_url = "";
  484.     stumbled_redirect = "";
  485. //    su_dd("reset", 2);
  486.     stumbles = new Array();
  487.     su_ratings = new Object();
  488.     
  489.     su_migrate_profile(new_profile);
  490.     
  491.     // make random delay...
  492.     // this is to avoid a race condition in hitting stumbles.php
  493.     // and hitting recommend.php to check_referral
  494.     // after X+su_random_delay seconds ... ( up to 5 minutes)
  495.     su_random_delay = Math.floor(Math.random()*300);
  496.  
  497.     su_stumble_action_count = 0;
  498.     try {
  499.         su_prefetcher.stop();
  500.         su_prefetcher.clearTargets();
  501.         su_prefetcher.passMax = su_ds.getValue("$prefetcher_pass_max");
  502.         su_prefetcher.pass1TimeoutInterval = su_ds.getValue("$prefetcher_pass_1_timeout_ms");
  503.         su_prefetcher.pass2TimeoutInterval = su_ds.getValue("$prefetcher_pass_2_timeout_ms");
  504.         su_prefetcher.pass3TimeoutInterval = su_ds.getValue("$prefetcher_pass_3_timeout_ms");
  505.         if (su_ds.getValue("$prefetcher_skip_resources"))
  506.             su_prefetcher.mode = "DOM";
  507.         else
  508.             su_prefetcher.mode = "complete";
  509.         su_prefetcher.addEventListener("progress-start", su_handle_prefetch_load_start);
  510.         
  511.         // If noscript is installed and the version is less than 1.9.8.4, then disable
  512.         // the prefetcher.  We do this because those versions have a bug which will cause
  513.         // the prefetcher to open up a bunch of extra tabs.  So we disable the
  514.         // prefetcher if one of those versions of noscript is installed.  Technically,
  515.         // the problematic versions are < 1.9.7.9, but then there was a regression around
  516.         // 1.9.8.1 that caused the problem again, but it was fixed again in 1.9.8.4, so we just
  517.         // disable prefetcher on anything earlier than 1.9.8.4.
  518.         var noscript_version = su_get_noscript_enabled_version();
  519.         if(noscript_version) 
  520.         {
  521.             var minVersion = su_ds.getValue("@min_noscript_for_prefetch");
  522.             var result = su_dotversion_compare(noscript_version, minVersion);
  523.             if(result && (result < 0))
  524.             {
  525.                 su_prefetcher.setQueueLock(true);
  526.             }
  527.         }
  528.     } catch (e) { su_log_error("INIT PREFETCHER"); }
  529.  
  530.     su_stumbleReporter.start();
  531.     
  532.     setTimeout(function (win) { win.su_load_ratings(); }, 0, window);
  533.  
  534.     try {
  535.         su_load_stumbles(null);
  536.     } catch (e) { su_log_error("LOAD STUMBLES", e); }
  537.     try {
  538.         su_load_categories();
  539.     } catch (e) { su_log_error("LOAD CATEGORIES", e); }
  540.     try {
  541.         su_load_user_interests();
  542.     } catch (e) { su_log_error("LOAD INTERESTS", e); }
  543.     su_tags = new Array();
  544.     su_tag_lists_by_url = new Object();
  545.     setTimeout(function (win) { win.su_load_tags(null); }, 0, window);
  546.  
  547.     su_queries = new Array();
  548.     setTimeout(function (win) { win.su_load_queries(); }, 0, window);
  549.     
  550.     if (su_ds.getValue("@whitelist_upon_load"))
  551.     {
  552.         try {
  553.             su_update_noscript_whitelists();
  554.         } catch (e) { su_log_error("INIT WHITELIST", e); }
  555.     }
  556.     
  557.     su_ds.flushPrefs();
  558. }
  559.  
  560. function su_update_noscript_whitelists()
  561. {
  562.     if (! su_ds.isPrefDefined("noscript.filterXExceptions"))
  563.         return;
  564.     
  565.     var str = su_ds.getValue("noscript.filterXExceptions");
  566.     var exceptions = str.split("\n");
  567.     var regsafeServer = su_servername.replace(/\./g, "\\.");
  568.     var filter_str = "^(http|https)://[a-z0-9\\-]+\\." + regsafeServer + "/";
  569.     var i;
  570.     var found = false;
  571.     for (i = 0; i < exceptions.length; i++)
  572.     {
  573.         if (exceptions[i] == filter_str)
  574.         {
  575.             found = true;
  576.             break;
  577.         }
  578.     }
  579.     
  580.     if (! found)
  581.     {
  582.         exceptions.push(filter_str);
  583.         str = exceptions.join("\n");
  584.         su_ds.setValue("noscript.filterXExceptions", str);
  585.     }
  586.     
  587.     if ((typeof noscriptUtil) != "object")
  588.         return;
  589.     
  590.     if (noscriptUtil.service &&
  591.             noscriptUtil.service.setJSEnabled &&
  592.             ((typeof noscriptUtil.service.setJSEnabled) == "function"))
  593.     {
  594.         noscriptUtil.service.setJSEnabled(su_servername, true);
  595.         noscriptUtil.service.setJSEnabled("recaptcha.net", true);
  596.     }
  597.     
  598.     su_ds.flushPrefs();
  599. }
  600.  
  601. // populates the stumbles array using content from file 'stumbleurls'
  602. function su_load_stumbles(url_to_exclude)
  603. {
  604.     stumbles = new Array();
  605.     // Load stumbleurls (queue of urls to be stumbled upon)
  606.     var unseen = su_read_file_user("stumbleurls");
  607.     
  608.     var commands = unseen.split("\n");
  609.  
  610.     try {
  611.         if (su_ds.getValue("$last_incat") == su_previous_query_category)
  612.             su_prefetcher.fetchAheadDepth = su_ds.getValue("$prefetcher_fetch_depth_in_query");
  613.         else
  614.             su_prefetcher.fetchAheadDepth = su_ds.getValue("$prefetcher_fetch_depth_in_topic");
  615.     } catch (e) {}
  616.     
  617.     var found_url_to_exclude = false;
  618.     var i;
  619.     var url_detail;
  620.     var target;
  621.     for (i = 0; i < commands.length; i++)
  622.     {
  623.         if (!commands[i].match(/^(http|https|ftp):/i))
  624.             continue;
  625.         
  626.         url_detail = su_deserialize_url_command_params(commands[i], true);
  627.  
  628.         // Skip any old stumbles that don't have a public id
  629.         if(!url_detail.publicid)
  630.             continue;
  631.         
  632.         target = url_detail.actual_url ? url_detail.actual_url : url_detail.url;
  633.         
  634.         if ((target == url_to_exclude) && (! found_url_to_exclude))
  635.         {
  636.             // exclude only the first instance of url_to_exclude
  637.             found_url_to_exclude = true;
  638.             continue;
  639.         }
  640.         
  641.         try {
  642.             if (su_is_404_status(su_prefetcher.getHttpResponseStatus(target)))
  643.             {
  644.                 su_report_404(target, su_prefetcher.getHttpResponseStatus(target));
  645.                 continue;
  646.             }
  647.         } catch (e) {}
  648.                 
  649.         
  650.         stumbles.push(commands[i]);
  651.         
  652.         // Don't prefetch against stumbleupon.com.
  653.         if (target.indexOf(su_base_url) == 0)
  654.             continue;
  655.         
  656.         // Don't prefetch profiles.
  657.         if (su_get_profile_nickname(target))
  658.             continue;
  659.         
  660.         // Don't prefetch 'is_sound' urls.
  661.         if (su_is_sound(target))
  662.             continue;    
  663.         
  664.         // Don't prefetch sponsored stumbles.
  665.         if (url_detail.cluster_type == 3)
  666.             continue;
  667.         
  668.         // Don't prefetch referrals.
  669.         if (url_detail.cluster_type == 4)
  670.             continue;
  671.         
  672.         if (! url_detail.referrer)
  673.         {
  674.             if (su_is_adult_category(url_detail.catid))
  675.                 url_detail.referrer = target;
  676.             else if (su_ds.getValue("@enable_refer"))
  677.                 url_detail.referrer = "http://www.stumbleupon.com/refer.php?url=" + encodeURIComponent(target);
  678.             else
  679.                 url_detail.referrer = "about:blank";
  680.         }
  681.         
  682.         try {
  683.             su_prefetcher.addTarget(url_detail);
  684.         } catch (e) { su_log_error("PREFETCHER 1", e); }
  685.     }
  686. }
  687.  
  688. // populates su_ratings using content from file 'stumblerating'
  689. function su_load_ratings()
  690. {
  691.     su_ratings = new Object();
  692.     // load ratings
  693.     var stumblecat = su_read_file_user("stumblerating");
  694.     var splitcat = stumblecat.split("\n");
  695.     for (var i = 0; i < splitcat.length; i++)
  696.     {
  697.         if (splitcat[i] == "")
  698.             continue;
  699.         var split2 = splitcat[i].split(" ");
  700.         su_ratings[split2[0]] = split2[1];
  701.     }
  702. }    
  703.  
  704. // populates su_user_interests using content from pref 'interests'
  705. function su_load_user_interests()
  706. {
  707.     su_user_interests = new Array();
  708.     
  709.     // Load su_user_interests
  710.     var stumbleseen = su_ds.getValue("$interests");
  711.     var splitseen = stumbleseen.split(" ");
  712.     var i;
  713.     for (i = 0; i < splitseen.length; i++)
  714.     {
  715.         if (splitseen[i] == "")
  716.             continue;
  717.         if (splitseen[i] == "toXMLRPCParam")
  718.             continue;
  719.         su_user_interests[splitseen[i]] = 1;
  720.     }
  721. }    
  722.  
  723. // populates su_tags and su_tag_lists_by_url using content of the
  724. // stumbletags file
  725. function su_load_tags(url_to_exclude)
  726. {
  727.     su_tags = new Array();
  728.     su_tag_lists_by_url = new Object();
  729.     
  730.     var stumblecat = su_read_file_user("stumbletags");
  731.     var splitcat = stumblecat.split("\n");
  732.     
  733.     for (var i = 0; i < splitcat.length; i++)
  734.     {
  735.         if (splitcat[i] == "")
  736.             continue;
  737.         var split2 = splitcat[i].split("\t");
  738.         var o = new Object();
  739.         o.url = split2[0];
  740.         o.tag_list = split2[1];
  741.         if ((o.url != url_to_exclude) && (o.url.indexOf("about:") != 0))
  742.         {
  743.             su_tag_lists_by_url[o.url] = o.tag_list;
  744.             su_tags.push(o);
  745.         }
  746.     }
  747. }
  748.  
  749. // stores content of su_tags into the stumbletags file
  750. function su_store_tags()
  751. {
  752.     var towrite = "";
  753.     for (var i = 0; (i < su_tags.length) && (i < su_ds.getValue("$tag_history_depth")); i++)
  754.         towrite += su_tags[i].url + "\t" + su_tags[i].tag_list + "\n";
  755.  
  756.     su_write_file_user("stumbletags", towrite);
  757. }
  758.  
  759. // populates su_queries using content of the stumblequeries file
  760. function su_load_queries()
  761. {
  762.     su_queries = new Array();
  763.     
  764.     var stumblequeries = su_read_file_user("stumblequeries");
  765.  
  766.     if (stumblequeries != "")
  767.         su_queries = stumblequeries.split("\n");
  768.     
  769.     // !! This is an inefficient method to get rid of the empty last 
  770.     // element due to the trailing linefeed in the file, but we'll 
  771.     // leave it this way for now, as it contributes robustness. -- JW
  772.     for (var i = 0; i < su_queries.length; i++)
  773.     {
  774.         if (su_queries[i] == "")
  775.             su_queries.splice(i, 1);
  776.     }
  777. }
  778.  
  779. // stores content of su_queries in the stumblequeries file
  780. function su_store_queries()
  781. {
  782.     var towrite = "";
  783.     for (var i = 0; (i < su_queries.length) && (i < su_ds.getValue("$query_history_depth")); i++)
  784.         towrite += su_queries[i] + "\n";
  785.  
  786.     su_write_file_user("stumblequeries", towrite);
  787. }
  788.  
  789. // initializes user-specific configuration that involves gui elements
  790. function su_load_data2(force_update)
  791. {
  792.     su_get_element("su_searchbox").autocompleteDatasource = 
  793.     { 
  794.         getResults : function ()
  795.         {
  796.             var searchbox = su_get_element("su_searchbox");
  797.             return su_get_autocomplete_results(
  798.                         su_ds.getValue("$autocomplete_type"),
  799.                         searchbox.value,
  800.                         searchbox.maxRows,
  801.                         new Array());
  802.         }
  803.     };
  804.     
  805. //    su_update_verified_reporting(false);
  806.     su_update_referred(false);
  807.     
  808.     su_check_referral(force_update);
  809.     su_process_rarely(force_update, false);
  810.  
  811.     if (force_update)
  812.     {
  813.         //!!! 1. Move contacts into getstate.php
  814.         //!!! 2. Sync tag & person subscriptions?
  815.         su_import_contacts();
  816.         su_get_state(false);
  817.     }
  818.     
  819.     // Store this stumbleid in the ids list.  The list is ordered from 
  820.     // most recently used to least recently used. -- JW
  821.     var id_list = su_ds.getValue("@id_list");
  822.     
  823.     var splitids = id_list.split(":");
  824.     var id_list_new = stumbleid + ":";
  825.     var i;
  826.     for (i = 0; i < splitids.length; i++)
  827.     {
  828.         if (splitids[i] == "")
  829.             continue;
  830.         
  831.         var line = splitids[i];
  832.         if (line != stumbleid)
  833.             id_list_new += splitids[i] + ":";
  834.     }
  835.     su_ds.setValue("@id_list", id_list_new);
  836.  
  837.     su_ds.flushPrefs();
  838.  
  839.     su_init_keybinding_globals();    
  840.  
  841.     su_configure_toolbar(false);
  842.     
  843.     su_close_all_messages();
  844.  
  845.     // Check to see when the url changes
  846.     su_add_progress_listener();
  847.  
  848.     // Upload any pending old stumbles
  849.     su_upload_stumbles();
  850.     
  851.     window.addEventListener("keyup", su_handle_window_keyup, false);
  852.     window.addEventListener("keypress", su_handle_window_keypress, false);
  853.     window.addEventListener("mousedown", su_handle_window_mousedown, true);
  854.     su_ds.addEventListener("resourceinstalled", su_handle_resource_installed, false);
  855.     
  856.     su_download_favs(false);    
  857.     su_process_command_queue();
  858. }
  859.  
  860. function su_process_command_queue()
  861. {
  862.     if (! su_host.places)
  863.         return;
  864.     
  865.     // wait for places migration to finish
  866.     if (su_ds.getValue("#migrating_places"))
  867.         return;
  868.     
  869.     var context;
  870.     
  871.     if (su_ds.getValue("#command_queue_context"))
  872.         return;
  873.     
  874.     var db = su_ds.getDatabase();
  875.     var sql;
  876.     var result;
  877.     sql = "SELECT seqid FROM command_queue WHERE priority>0 ORDER BY priority DESC, seqid LIMIT 1";
  878.     result = db.query(sql);
  879.     if (result.length == 0)
  880.     {
  881.         su_ds.setValue("#download_favs_detail", null);
  882. //        su_ds.setValue("#command_queue_context", null);
  883.         return;
  884.     }
  885.     
  886.     context = new Object();
  887.  
  888.     su_ds.setValue("#command_queue_context", context);
  889.     
  890.     context.priority == null;
  891.     context.command_rows = null;
  892.     context.processed_idx = 0;
  893.     context.download_favs_detail = null;
  894. //    context.abort = false;
  895.     setTimeout(su_process_command_queue2, 200, context);
  896. }
  897.  
  898. function su_process_command_queue2(context)
  899. {
  900.     var db = su_ds.getDatabase();
  901.     var sql;
  902.     var seqid;
  903.     var command;
  904.     var row;
  905.     var detail;
  906.     var val;
  907.     
  908.     // 1. grab a set of commands
  909.     if (! context.command_rows)
  910.     {
  911.         sql = "SELECT priority,seqid,command FROM command_queue WHERE priority>0 ORDER BY priority DESC, seqid LIMIT 1000";
  912.         context.command_rows = db.query(sql);
  913.         context.processed_idx = 0;
  914.     }
  915.     
  916.     // 2. check whether we're done.
  917. //    if ((context.command_rows.length == 0) || context.abort)
  918.     if (context.command_rows.length == 0) 
  919.     {
  920.         su_ds.setValue("#command_queue_context", null);
  921.         // moving out of favs
  922.         if (context.download_favs_detail)
  923.         {
  924.             su_set_download_favs_enabled(true);
  925.             context.download_favs_detail = null;
  926.         }
  927.         setTimeout(su_process_command_queue, 0);
  928.         return;
  929.     }
  930.     
  931.     row = context.command_rows[context.processed_idx];
  932.     
  933.     if (context.download_favs_detail && (row.priority != 16000))
  934.     {
  935.         // moving out of favs
  936.         su_set_download_favs_enabled(true);
  937.         
  938.         context.download_favs_detail = null;
  939.     }
  940.     else if ((context.priority != 16000) && (row.priority == 16000))
  941.     {
  942.         // moving into favs
  943.         su_set_download_favs_enabled(false);
  944.         
  945.         detail = su_ds.getValue("#download_favs_detail");
  946.         if (! detail)
  947.         {
  948.             detail = su_ds.getValue("$download_favs_detail");
  949.             su_ds.setValue("#download_favs_detail", detail);
  950.         }
  951.         context.download_favs_detail = detail;
  952.     }
  953.     
  954.     context.priority = row.priority;
  955.     
  956.     if (context.download_favs_detail)
  957.     {
  958.         detail = context.download_favs_detail;
  959.         detail.apply_count++;
  960.         if ((detail.applied_count % 1000) == 0)
  961.         {
  962.             su_ds.setValue("$download_favs_detail", detail);
  963.             su_ds.flushPrefs();
  964.         }
  965.         
  966.         if (su_preference_dialog)
  967.         {
  968.             val = 5 + Math.round((45 * (detail.download_count / detail.download_target_count)) + (45 * (detail.apply_count / detail.apply_target_count)));
  969.             
  970.             el = su_preference_dialog.ownerDocument.getElementById("download_progress");
  971.             if (el && (val != el.value))
  972.                 el.setAttribute("value", val);
  973.         }
  974.     }
  975.     
  976.     // 3. process the command
  977.     su_process_command(row.command, context);
  978.     
  979.     // 4. remove it from the queue
  980.     sql = "DELETE FROM command_queue WHERE seqid=" + db.v(row.seqid);
  981.     db.query(sql);
  982.     context.processed_idx++;
  983.     
  984.     if (context.command_rows.length == context.processed_idx)
  985.         context.command_rows = null;
  986.     
  987.     setTimeout(su_process_command_queue2, 50, context);
  988. }
  989.  
  990. function su_set_download_favs_enabled(enabled)
  991. {
  992.     var el;
  993.     var doc;
  994.     var sync;
  995.     
  996.     if (! su_preference_dialog)
  997.         return;
  998.     
  999.     doc = su_preference_dialog.ownerDocument; 
  1000.     
  1001.     sync = doc.getElementById("sync_bm_meta").checked;
  1002.     
  1003.     if (enabled)
  1004.         doc.getElementById("download_progress").value = 0;
  1005.  
  1006.     doc.getElementById("download_start").disabled = (! sync) || (! enabled);
  1007.     
  1008.     doc.getElementById("download_stop").disabled = (! sync) || enabled;
  1009. }
  1010.  
  1011. // used during init to set hidden states for top-level toolbar
  1012. // element
  1013. function su_init_toolbar_element_visibility()
  1014. {
  1015.     if ((stumbleid == 0) && su_promo_mode)
  1016.     {
  1017.         su_set_visible("su_start",         true);
  1018.         su_set_visible("su_login",         true);
  1019.         su_set_visible("su_stumble",       false);
  1020.         su_set_visible("su_sites_promo",   true);
  1021.         su_set_visible("su_friends",       true);
  1022.         su_set_visible("su_thumbup",       true);
  1023.         su_set_visible("su_thumbdown",     false);
  1024.         su_get_element("su_thumbdown").type = "";
  1025.         su_set_visible("su_separator2",    true);
  1026.         su_set_visible("su_website_info_promo", true);
  1027.         su_set_visible("su_separator_promo", true);
  1028.         su_set_visible("su_referral_promo", true);
  1029.         su_set_visible("su_separator_category", true);
  1030.         su_set_visible("su_separator4",    true);
  1031.         su_set_visible("su_video_promo",   true);
  1032.         su_set_visible("su_separator6",    true);
  1033.         su_set_visible("su_profile",       true);
  1034.         su_set_visible("su_separator7",    false);
  1035.         su_set_visible("su_mode",          false);    
  1036.         su_set_visible("su_stumble_menu",  false);
  1037.         su_set_visible("su_category",      false);
  1038.         su_set_visible("su_website_info",  false);
  1039.         su_set_visible("su_network",       false); // legacy network
  1040.         su_set_visible("su_messages",      false);    
  1041.         su_set_visible("su_field",         false);
  1042.         su_has_searchbox = false;
  1043.     
  1044.         su_set_visible("su_filter",        false);
  1045.         su_set_visible("su_aboutme",       false);
  1046.         su_set_visible("su_matches",       false);
  1047.         su_set_visible("su_groups",        false);
  1048.         su_set_visible("su_myinfo",        false);
  1049. //        su_set_visible("su_forum",         false);   // legacy forums
  1050.         su_set_visible("su_referral_menu", false);
  1051. //        su_set_visible("su_inbox-count",   false);
  1052.         su_set_visible("su_referred", false);
  1053.     
  1054.         su_set_visible("su_page_feature_prompt", false);
  1055.         su_set_visible("firstrater",       false);
  1056.         su_set_visible("su_stumble_topic", false);
  1057.         su_set_visible("su_stumble_topic_menu_left", false);
  1058.         su_set_visible("su_stumble_topic_menu_right", false);
  1059.         su_set_visible("su_sponsor",       false);
  1060.         su_set_visible("su_tag",           false);
  1061.         su_set_visible("su_tag2",          false);
  1062.         su_set_visible("su_splitter_search_right", false);
  1063.     }
  1064.     else if (stumbleid == 0)
  1065.     {
  1066.         su_set_visible("su_start",         true);
  1067.         su_set_visible("su_login",         (! su_has_logged_in()));
  1068.         su_set_visible("su_stumble",       false);
  1069.         su_set_visible("su_sites_promo",   false);
  1070.         su_set_visible("su_friends",       false);
  1071.         su_set_visible("su_thumbup",       false);
  1072.         su_set_visible("su_thumbdown",     false);
  1073.         su_get_element("su_thumbdown").type = "";
  1074.         su_set_visible("su_separator2",    false);
  1075.         su_set_visible("su_website_info_promo", false);
  1076.         su_set_visible("su_separator_promo", false);
  1077.         su_set_visible("su_referral_promo", false);
  1078.         su_set_visible("su_separator4",    false);
  1079.         su_set_visible("su_separator_category", false);
  1080.         su_set_visible("su_video_promo",   false);
  1081.         su_set_visible("su_separator6",    false);
  1082.         su_set_visible("su_separator7",    false);
  1083.         su_set_visible("su_profile",       false);
  1084.         su_set_visible("su_mode",          false);
  1085.         su_set_visible("su_stumble_menu",  false);
  1086.         su_set_visible("su_category",      false);
  1087.         su_set_visible("su_website_info",  false);    
  1088.         su_set_visible("su_network",       false); // legacy network
  1089.         su_set_visible("su_messages",      false);    
  1090.         su_set_visible("su_field",         false);
  1091.         su_has_searchbox = false;
  1092.         su_set_visible("su_filter",        false);
  1093.         su_set_visible("su_aboutme",       false);    
  1094.         su_set_visible("su_matches",       false);    
  1095.         su_set_visible("su_groups",        false);    
  1096.         su_set_visible("su_myinfo",        false);
  1097. //        su_set_visible("su_forum",         false);   // legacy forums
  1098.         su_set_visible("su_referral_menu", false);
  1099. //        su_set_visible("su_inbox-count",   false);
  1100.         su_set_visible("su_referred", false);
  1101.         su_set_visible("su_page_feature_prompt", false);
  1102.         su_set_visible("firstrater",       false);
  1103.         su_set_visible("su_stumble_topic", false);
  1104.         su_set_visible("su_stumble_topic_menu_left", false);
  1105.         su_set_visible("su_stumble_topic_menu_right", false);
  1106.         su_set_visible("su_sponsor",       false);
  1107.         su_set_visible("su_tag",           false);
  1108.         su_set_visible("su_tag2",          false);
  1109.         su_set_visible("su_splitter_search_right", false);
  1110.     }
  1111.     else
  1112.     {
  1113.         // show rating buttons, menu, etc...
  1114.         su_set_visible("su_start",         false);
  1115.         su_set_visible("su_login",         false);
  1116.         su_set_visible("su_stumble",       true);
  1117.         su_set_visible("su_separator4",    (
  1118.                                                (su_ds.getValue("$show_mode")  &&
  1119.                                                su_ds.getValue("$show_separators"))
  1120.                                            )
  1121.                       );
  1122.         su_set_visible("su_separator_category", su_ds.getValue("$show_topics") || !su_get_element("su_stumble_topic_menu_left").collapsed);
  1123.         su_set_visible("su_thumbup",       true);
  1124.         su_set_visible("su_thumbdown",     true);
  1125.         su_get_element("su_thumbdown").type = "menu-button";
  1126.         su_set_visible("su_separator2",    su_ds.getValue("$show_separators"));
  1127.         su_set_visible("su_referral_promo", false);
  1128.         su_set_visible("su_separator_promo",  false);
  1129.         su_set_visible("su_website_info_promo", false);
  1130.         su_set_visible("su_stumble_menu",  true);
  1131.         su_set_visible("su_category",      su_ds.getValue("$show_topics"));
  1132.         su_set_visible("su_website_info",  su_ds.getValue("$show_info"));
  1133.         su_set_visible("su_field",         su_ds.getValue("$show_field"));
  1134.         su_has_searchbox = su_ds.getValue("$show_field");
  1135.         su_set_visible("su_splitter_search_right", su_ds.getValue("$show_field"));
  1136.         su_set_visible("su_tag",           (su_ds.getValue("$show_tag") && su_ds.getValue("$show_field")) );
  1137.         su_set_visible("su_tag2",  (su_ds.getValue("$show_tag") && (! su_ds.getValue("$show_field"))) );
  1138.         su_set_visible("su_referral_menu", su_ds.getValue("$show_referral"));
  1139.         su_set_visible("su_separator6",    (! (
  1140.                                                 (
  1141.                                                     (! su_ds.getValue("$show_field")) &&
  1142.                                                     (! su_ds.getValue("$show_info")) &&
  1143.                                                     (! su_ds.getValue("$show_referral")) &&
  1144.                                                     (! su_ds.getValue("$show_tag"))
  1145.                                                 ) ||
  1146.                                                 (
  1147.                                                     su_ds.getValue("$show_field") &&
  1148.                                                     (!su_ds.getValue("$show_tag"))
  1149.                                                 ) ||
  1150.                                                 (! su_ds.getValue("$show_separators"))
  1151.                                                )
  1152.                                             )
  1153.                       );
  1154.         su_set_visible("su_aboutme",       su_ds.getValue("$show_aboutme"));
  1155.         su_set_visible("su_sites_promo",   false);
  1156.         su_set_visible("su_video_promo",   false);
  1157.         su_set_visible("su_page_feature_prompt", false);
  1158.         su_set_visible("su_filter",        su_ds.getValue("$show_filter"));
  1159.         su_set_visible("firstrater",       false);
  1160.         su_set_visible("su_separator7",    false);
  1161.         su_set_visible("su_stumble_topic", false);
  1162.         su_set_visible("su_stumble_topic_menu_left", false);
  1163.         su_set_visible("su_stumble_topic_menu_right", false);
  1164.         su_set_visible("su_sponsor",       false);
  1165.         su_set_visible("su_profile",       su_ds.getValue("$show_home"));
  1166.         su_set_visible("su_friends",       su_ds.getValue("$show_friends"));
  1167.         su_set_inbox_status((su_ds.getValue("$newmessage")) ? '2' : '');
  1168. //        su_set_visible("su_messages",      su_ds.getValue("$show_messages"));
  1169.         su_set_visible("su_network",       su_ds.getValue("$show_legacy_network"));
  1170.         su_set_visible("su_matches",       su_ds.getValue("$show_matches"));
  1171. //        su_set_visible("su_forum",         su_ds.getValue("$show_legacy_forums"));
  1172.         su_set_visible("su_groups",        su_ds.getValue("$show_groups"));
  1173.         su_set_visible("su_myinfo",        su_ds.getValue("$show_myinfo"));
  1174.     
  1175.         var mode_ids = [
  1176.                     "mode",
  1177.     //                "mode_all",
  1178.                     "mode_friends",
  1179.                     "mode_news",
  1180.                     "mode_photo",
  1181.                     "mode_search",
  1182.                     "mode_stumblers",
  1183.                     "mode_video",
  1184.                     "mode_wiki",
  1185.                     "mode_more"];
  1186.         var i;
  1187.         for (i = 0; i < mode_ids.length; i++)
  1188.             su_set_visible("su_" + mode_ids[i], su_ds.getValue("$show_" + mode_ids[i]));
  1189.         su_set_visible("su_mode_all", true);
  1190.  
  1191.         su_set_visible("su_recthumbup", su_ds.getValue("$dd_rec_rating") != 0);
  1192.     }
  1193. }
  1194.  
  1195. function su_refresh_dyn_channels()
  1196. {
  1197.     su_invoke_global_event("dyn-channels-dirty", null);
  1198.     
  1199.     if (su_refreshing_dyn_channels)
  1200.         return;
  1201.     
  1202.     su_refreshing_dyn_channels = true;
  1203.     
  1204.     setTimeout(
  1205.                 function (win) {
  1206.                     win.su_invoke_global_event("update-dyn-channels", null); },
  1207.                 500,
  1208.                 window);
  1209. }
  1210.  
  1211. function su_update_dyn_channels()
  1212. {
  1213.     su_refreshing_dyn_channels = false;
  1214.  
  1215.     if (! su_dyn_channels_dirty)
  1216.         return;
  1217.     
  1218.     if (su_mode_more_popup_open)
  1219.         return;
  1220.     
  1221.     su_dyn_channels_dirty = false;
  1222.     
  1223.     var channels = su_ds.getThruDomainChannels(true);
  1224.     
  1225.     if (! channels)
  1226.     {
  1227.         if (! su_ds.getValue("#checked_dyn_channels"))
  1228.             su_check_dyn_channels();
  1229.         return;
  1230.     }
  1231.     
  1232.     var parent = su_get_element("su_mode");
  1233.     var brother_el = su_get_element("su_mode_all");
  1234.     var id;
  1235.     var channel_id;
  1236.     var el;
  1237.     var i;
  1238.     for (i = 0; i < channels.length; i++)
  1239.     {
  1240.         channel_id = su_get_channel_id(channels[i].domain); 
  1241.         id = "su_mode_dyn_" + channel_id;
  1242.         el = su_get_element(id);
  1243.         if (el)
  1244.             el.parentNode.removeChild(el);
  1245.  
  1246.         id = "su_mode_more_" + channel_id;
  1247.         el = su_get_element(id);
  1248.         if (el)
  1249.             el.parentNode.removeChild(el);
  1250.     }
  1251.     
  1252.     var more_popup = su_get_element("su_mode_more_popup");
  1253.     while (more_popup.lastChild)
  1254.         more_popup.removeChild(more_popup.lastChild);
  1255.     
  1256.     for (i = 0; i < channels.length; i++)
  1257.     {
  1258.         channel_id = su_get_channel_id(channels[i].domain); 
  1259.         var icon_url = su_ds.getResourceURLFromName("favicons", 
  1260.                     channel_id + ".ico")
  1261.         
  1262.         id = "su_mode_more_" + channel_id;
  1263.         el = document.createElement("menuitem");
  1264.         el.setAttribute("id", id);
  1265.         el.setAttribute("label", " " + channels[i].name);
  1266.         el.setAttribute("onclick", "su_handle_domain_mode_click(event, '" + channels[i].domain + "');");
  1267.         el.setAttribute("tooltiptext", "StumbleThru " + channels[i].name);
  1268.         el.setAttribute("class", "menuitem-iconic");
  1269.         el.setAttribute("image", icon_url);
  1270.         more_popup.appendChild(el);
  1271.         
  1272.         if (channels[i].show)
  1273.         {
  1274.             // If they've added a dyn channel button, we don't need to
  1275.             // educate via the info bubble. -- Jw
  1276.             su_ds.setValue("$shown_thru_domain_info_count", su_ds.getValue("~shown_thru_domain_info_count_max"));
  1277.             
  1278.             id = "su_mode_dyn_" + channel_id;
  1279.             el = document.createElement("toolbarbutton");
  1280.             el.setAttribute("id", id);
  1281.             el.setAttribute("class", "su-hidetext");
  1282.             el.setAttribute("su_ismode", "1");
  1283.             el.setAttribute("onclick", "su_handle_domain_mode_click(event, '" + channels[i].domain + "');");
  1284.             el.setAttribute("tooltiptext", "StumbleThru " + channels[i].name);
  1285.             el.setAttribute("image", icon_url);
  1286.             parent.insertBefore(el, brother_el);
  1287.             su_set_image(id, icon_url);
  1288.         }
  1289.     }
  1290.     su_refreshing_dyn_channels = false;
  1291.     su_update_thru_domain(su_get_browser_url(), null, null, null, true);
  1292.     su_reflow_toolbar(14);
  1293. }
  1294.  
  1295. // used by move_toolbar() to initialize splitters
  1296. function su_init_splitters()
  1297. {
  1298.     try {
  1299.     var sidebar_splitter = su_get_element("sidebar-splitter");
  1300.     
  1301.     if (sidebar_splitter)
  1302.     {
  1303.         sidebar_splitter.addEventListener("DOMAttrModified", su_handle_sidebar_attr_modified, false);
  1304.         sidebar_splitter.addEventListener("mouseup", su_handle_sidebar_mouseup, false);
  1305.     }
  1306.     
  1307.     var width = su_ds.getValue("@search-width");
  1308.     if (width == 0)
  1309.     {
  1310.         width = 156;
  1311.         su_ds.setValue("@search-width", width);
  1312.     }
  1313.     if (width > 400)
  1314.     {
  1315.         width = 400;
  1316.         su_ds.setValue("@search-width", width);
  1317.     }
  1318.     su_get_element("su_field").setAttribute("width", width + "px");
  1319.  
  1320.     su_get_element("su_splitter_first_flexbox").collapsed = false;
  1321.  
  1322.     setTimeout(function (win) { win.su_refresh_splitters(true); }, 0, window);
  1323.     } catch (e) { su_log_error("INIT SPLITTERS", e, su_ds.getValue("@toolbar-position"), su_ds.getValue("@position-group")); }
  1324. }    
  1325.  
  1326. // used during init to initialize globals and to survey existing 
  1327. // keybindings
  1328. function su_init_keybinding_globals()
  1329. {
  1330.     su_init_key_const_dictionaries();
  1331.  
  1332.     var keys = document.getElementsByTagName("key");
  1333.     
  1334.     for (var i = 0; i < keys.length; i++)
  1335.         su_keys_by_keyspec[su_get_keyspec_from_key(keys[i])] = keys[i];
  1336. }
  1337.  
  1338. // used by init_keybinding_globals to populate
  1339. // su_keyids_by_eventkeycode, su_chars_by_keyid and su_keyids_by_char
  1340. function su_init_key_const_dictionaries()
  1341. {
  1342.     var keyid;
  1343.     var property;
  1344.     for (property in KeyEvent)
  1345.     {
  1346.         if (su_is_property_garbage(KeyEvent, property))
  1347.             continue;
  1348.         
  1349.         keyid = property.replace("DOM_","");
  1350.         su_keyids_by_eventkeycode[KeyEvent[property]] = keyid;
  1351.         if (keyid.length == 4)
  1352.             su_chars_by_keyid[keyid] = String.fromCharCode(KeyEvent[property]);
  1353.     }
  1354.     su_keyids_by_eventkeycode[8] = "VK_BACK";
  1355.     
  1356.     var o = su_chars_by_keyid;    
  1357.     o["VK_SEMICOLON"] = ";";
  1358.     o["VK_EQUALS]"] = "=";
  1359.     o["VK_MULTIPLY"] = "*";
  1360.     o["VK_ADD"] = "+";
  1361.     o["VK_SUBTRACT"] = "-";
  1362.     o["VK_DECIMAL"] = ".";
  1363.     o["VK_DIVIDE"] = "/";
  1364.     o["VK_COMMA"] = ",";
  1365.     o["VK_PERIOD"] = ".";
  1366.     o["VK_SLASH"] = "/"; // overwrites VK_DIVIDE in su_keyids_by_char
  1367.     o["VK_BACK_QUOTE"] = "`";
  1368.     o["VK_OPEN_BRACKET"] = "[";
  1369.     o["VK_BACK_SLASH"] = "\\";
  1370.     o["VK_CLOSE_BRACKET"] = "]";
  1371.     o["VK_QUOTE"] = '"';
  1372.  
  1373.     su_keyids_by_char = su_invert_dictionary(su_chars_by_keyid);
  1374. }
  1375.  
  1376. // used by init_keybinding_globals to get the keyspec from a key 
  1377. // element
  1378. function su_get_keyspec_from_key(key)
  1379. {
  1380.   var str = "";
  1381.  
  1382.     var modifiers = key.getAttribute("modifiers").toLowerCase();
  1383.  
  1384.     if (modifiers.indexOf("alt") != -1)     str += "Alt+";
  1385.     if (modifiers.indexOf("control") != -1) str += "Ctrl+";
  1386.     if (modifiers.indexOf("meta") != -1)    str += "Command+";
  1387.     if (modifiers.indexOf("accel") != -1)
  1388.     {
  1389.         if (su_host.mac)
  1390.             str += "Command+";
  1391.         else
  1392.             str += "Ctrl+"
  1393.     }
  1394.     if (modifiers.indexOf("shift") != -1)   str += "Shift+";
  1395.  
  1396.     var keyid;
  1397.     if (key.hasAttribute("key") && (key.getAttribute("key").length == 1))
  1398.     {
  1399.         keyid = key.getAttribute("key").toUpperCase();
  1400.         var keyid_tmp = su_keyids_by_char[keyid];
  1401.         if (keyid_tmp)
  1402.             keyid = keyid_tmp;
  1403.     }
  1404.     else if (key.hasAttribute("keycode"))
  1405.     {
  1406.         keyid = key.getAttribute("keycode");
  1407.     }
  1408.     
  1409.     if (! keyid)
  1410.         keyid = "";
  1411.     
  1412.     str += keyid;
  1413.  
  1414.     return str;
  1415. }
  1416.  
  1417. // called by the global configure-toolbar event and during init
  1418. // to update the key bindings
  1419. function su_refresh_keybindings()
  1420. {
  1421.     // It would be more friendly to other extensions if we'd add key
  1422.     // elements rather than attach a keyup listener to the window.
  1423.     // But we have to use a keyup listener in order to distinguish
  1424.     // between 'numeral keys on the number row' and 'numeral keys on 
  1425.     // the numeric keypad w/ numlock turned on'.  This is necessary to
  1426.     // avoid a conflict between binding Alt+VK_1 and typing a special
  1427.     // character via Alt+[keycode] using the numeric keypad on XP.
  1428.     // We're supposed to be able to distinguish between the number row
  1429.     // and the keypad keys using different keycodes (i.e. VK_1 vs 
  1430.     // VK_NUMPAD1) [1], but if one of those keycodes is specified on a 
  1431.     // key element, its command is never invoked (ref Firefox 1.5, XP).
  1432.     // -- JW
  1433.     // [1]
  1434.     // http://www.xulplanet.com/tutorials/xultu/keyshort.html
  1435.     
  1436.     var stumble_default;
  1437.     var reviews_default;
  1438.     var thumbup_default;
  1439.     var thumbdown_default;
  1440.     var tag_default;
  1441. //    var details_default;
  1442.     var toolbar_default;
  1443.     if (su_host.mac)
  1444.     {
  1445.         stumble_default = "Alt+VK_ESCAPE";
  1446.         thumbup_default = "Alt+VK_F1";
  1447.         thumbdown_default = "Alt+VK_F2";
  1448.         tag_default =     "ALT+VK_SLASH";
  1449.         reviews_default = "Alt+VK_F3";
  1450. //        details_default = "Alt+VK_F4";
  1451.         toolbar_default = "Command+VK_F11";
  1452.     }
  1453.     else if (su_host.win)
  1454.     {
  1455.         stumble_default = "Alt+VK_BACK_QUOTE";
  1456.         thumbup_default = "Alt+VK_1";
  1457.         thumbdown_default = "Alt+VK_2";
  1458.         tag_default =     "ALT+VK_SLASH";
  1459.         reviews_default = "Alt+VK_3";
  1460.         //        details_default = "Alt+VK_4";
  1461.         toolbar_default = "Ctrl+VK_F11";
  1462.     }
  1463.     else
  1464.     {
  1465.         stumble_default = "Alt+VK_ESCAPE";
  1466.         thumbup_default = "Alt+VK_F1";
  1467.         thumbdown_default = "Alt+VK_F2";
  1468.         tag_default =     "ALT+VK_SLASH";
  1469.         reviews_default = "Alt+VK_F3";
  1470. //        details_default = "Alt+VK_F4";
  1471.         toolbar_default = "Ctrl+VK_F11";
  1472.     }
  1473.     var keyspecs = new Array();
  1474.     su_commands_by_keyspec = new Object();
  1475.     var keyspec;
  1476.     
  1477.     var rating_enabled = su_ds.getValue("$shortcuts_enabled");
  1478.     
  1479.     keyspec = su_ds.getPrefValue("$shortcut_stumble", stumble_default);
  1480.     if (rating_enabled && (keyspec != ""))
  1481.     {
  1482.         keyspecs.push(keyspec);
  1483.         su_commands_by_keyspec[keyspec] = su_get_element("StumbleUpon:Stumble");
  1484.     }
  1485.  
  1486.     keyspec = su_ds.getPrefValue("$shortcut_thumbup", thumbup_default);
  1487.     if (rating_enabled && (keyspec != ""))
  1488.     {
  1489.         keyspecs.push(keyspec);
  1490.         su_commands_by_keyspec[keyspec] = su_get_element("StumbleUpon:RateThumbup");
  1491.     }
  1492.  
  1493.     keyspec = su_ds.getPrefValue("$shortcut_thumbdown", thumbdown_default);
  1494.     if (rating_enabled && (keyspec != ""))
  1495.     {
  1496.         keyspecs.push(keyspec);
  1497.         su_commands_by_keyspec[keyspec] = su_get_element("StumbleUpon:RateThumbdown");
  1498.     }
  1499.  
  1500.     keyspec = su_ds.getPrefValue("$shortcut_tag", tag_default);
  1501.     if (rating_enabled && (keyspec != ""))
  1502.     {
  1503.         keyspecs.push(keyspec);
  1504.         su_commands_by_keyspec[keyspec] = su_get_element("StumbleUpon:Tag");
  1505.     }
  1506.  
  1507.     keyspec = su_ds.getPrefValue("$shortcut_reviews", reviews_default);
  1508.     if (rating_enabled && (keyspec != ""))
  1509.     {
  1510.         keyspecs.push(keyspec);
  1511.         su_commands_by_keyspec[keyspec] = su_get_element("StumbleUpon:ViewReviews");
  1512.     }
  1513.  
  1514. //    keyspec = su_ds.getPrefValue("$shortcut_details", details_default);
  1515. //    if (rating_enabled && (keyspec != ""))
  1516. //    {
  1517. //        keyspecs.push(keyspec);
  1518. //        su_commands_by_keyspec[keyspec] = su_get_element("StumbleUpon:RateThumbupDetailed");
  1519. //    }
  1520.  
  1521.     keyspec = su_ds.getPrefValue("$shortcut_toolbar", toolbar_default);
  1522.     if (keyspec != "")
  1523.     {
  1524.         keyspecs.push(keyspec);
  1525.         su_commands_by_keyspec[keyspec] = su_get_element("StumbleUpon:ToggleToolbar");
  1526.     }
  1527.  
  1528.     if (su_ds.getValue("$shortcut_toolbar") != toolbar_default)
  1529.     {
  1530.         var toggle_key = su_get_element("key_StumbleUpon:ToggleToolbar");
  1531.         
  1532.         if (toggle_key.hasAttribute("command"))
  1533.         {
  1534.             toggle_key.setAttribute("savedcommand", toggle_key.getAttribute("command"));
  1535.             toggle_key.removeAttribute("command");
  1536.         }
  1537.     }
  1538.  
  1539.     if (su_get_element("stumbleupon"))
  1540.     {
  1541.         var toolbar_keyspec = su_ds.getValue("$shortcut_toolbar");
  1542.         if (toolbar_keyspec == "")
  1543.         {
  1544.             su_get_element("stumbleupon").setAttribute("toolbarname", "StumbleUpon Toolbar");
  1545.         }
  1546.         else
  1547.         {
  1548.             su_get_element("stumbleupon").setAttribute("toolbarname", "StumbleUpon Toolbar (" + 
  1549.                         su_get_display_keyspec(su_ds.getValue("$shortcut_toolbar")) + 
  1550.                         ")");
  1551.         }
  1552.     }
  1553.  
  1554.     for (keyspec in su_removed_keybindings_by_keyspec)
  1555.     {
  1556.         if (su_is_property_garbage(su_removed_keybindings_by_keyspec, keyspec))
  1557.             continue;
  1558.         
  1559.         if (su_removed_keybindings_by_keyspec[keyspec])
  1560.         {
  1561.             su_removed_keybindings_by_keyspec[keyspec].alive = false;
  1562.         }
  1563.     }
  1564.     
  1565.     for (var i = 0; i < keyspecs.length; i++)
  1566.     {
  1567.         var key;
  1568.         var binding;
  1569.         if (su_keys_by_keyspec[keyspecs[i]])
  1570.         {
  1571.             key = su_keys_by_keyspec[keyspecs[i]];
  1572.             binding = new Object();
  1573.             binding.alive = true;
  1574.             binding.key = key;
  1575.  
  1576.             if (key.hasAttribute("command"))
  1577.             {
  1578.                 binding.command = key.getAttribute("command");
  1579.                 key.removeAttribute("command");
  1580.             }
  1581.  
  1582.             if (key.hasAttribute("oncommand"))
  1583.             {
  1584.                 binding.oncommand = key.getAttribute("oncommand");
  1585.                 key.removeAttribute("oncommand");
  1586.             }
  1587.  
  1588.             if (key.hasAttribute("onkeypress"))
  1589.             {
  1590.                 binding.onkeypress = key.getAttribute("onkeypress");
  1591.                 key.removeAttribute("onkeypress");
  1592.             }
  1593.  
  1594.             su_removed_keybindings_by_keyspec[keyspecs[i]] = binding;
  1595.         }
  1596.     }
  1597.     
  1598.     for (keyspec in su_removed_keybindings_by_keyspec)
  1599.     {
  1600.         if (su_is_property_garbage(su_removed_keybindings_by_keyspec, keyspec))
  1601.             continue;
  1602.         
  1603.         if (su_removed_keybindings_by_keyspec[keyspec])
  1604.         {
  1605.             var binding = su_removed_keybindings_by_keyspec[keyspec];
  1606.             
  1607.             if (! binding.alive)
  1608.             {
  1609.                 if (binding.command)
  1610.                     binding.key.setAttribute("command", binding.command);
  1611.  
  1612.                 if (binding.oncommand)
  1613.                     binding.key.setAttribute("oncommand", binding.oncommand);
  1614.  
  1615.                 if (binding.onkeypress)
  1616.                     binding.key.setAttribute("onkeypress", binding.onkeypress);
  1617.  
  1618.                 delete su_removed_keybindings_by_keyspec[keyspec];
  1619.             }
  1620.         }
  1621.     }
  1622. }
  1623.  
  1624. // used by refresh_keybindings and the preferenceDialog to convert a
  1625. // keyspec into its readable form
  1626. function su_get_display_keyspec(keyspec)
  1627. {
  1628.     var keyid = su_get_keyid_from_keyspec(keyspec);
  1629.     if (su_chars_by_keyid[keyid])
  1630.     {
  1631.         var regexp = new RegExp(su_escape_regexp_chars(keyid) + "$");
  1632.         keyspec = keyspec.replace(regexp, su_chars_by_keyid[keyid]);
  1633.     }
  1634.     return keyspec.replace("VK_", "").replace(/BACK$/, "BACKSPACE");
  1635. }
  1636.  
  1637. // given a keyspec, returns a string that specifies the corresponding
  1638. // modifiers for a key object
  1639. function su_get_modifiers_from_keyspec(keyspec)
  1640. {
  1641.     var parts = keyspec.split("+")
  1642.  
  1643.     var str = "";
  1644.     for (var i = 0; i < parts.length; i++)
  1645.     {
  1646.         switch (parts[i])
  1647.         {
  1648.             case "Alt":     str += "alt ";     break;
  1649.             case "Ctrl":    str += "control "; break;
  1650.             case "Command": str += "meta ";    break;
  1651.             case "Shift":   str += "shift ";   break;
  1652.         }
  1653.     }
  1654.  
  1655.     if (str != "")
  1656.     {
  1657.         str = str.substring(0, str.length);
  1658.     }
  1659.     return str;
  1660. }
  1661.  
  1662. // given a keyspec, returns the keyid portion
  1663. function su_get_keyid_from_keyspec(keyspec)
  1664. {
  1665.     var parts = keyspec.split("+");
  1666.     if (parts[parts.length - 1] == "")
  1667.         return "+";  // probably cruft -- JW
  1668.     else
  1669.         return parts[parts.length - 1];
  1670. }
  1671.  
  1672. function su_handle_content_click(event)
  1673. {
  1674.     if (stumbleid == 0)
  1675.         return true;
  1676.     
  1677. //    getBrowser().selectedBrowser.su_content_clicked = true;
  1678.     
  1679.     try {
  1680.         if (su_is_server_page(event.target.href, "login.php?logout=1"))
  1681.         {
  1682.             setTimeout(su_handle_page_logout_click, 0);
  1683.             return su_cancel_event(event);
  1684.         }
  1685.     } catch (e) {}
  1686.  
  1687.     var ondblclick = "";
  1688.     
  1689.     if (event.originalTarget.hasAttribute("ondblclick"))
  1690.         ondblclick = event.originalTarget.getAttribute("ondblclick");
  1691.     
  1692.     var current_page = su_get_browser_url(event.target.ownerDocument, true);
  1693.     
  1694.     var slq = su_ds.globals.sluqh[current_page];
  1695.     
  1696.     if (slq && (ondblclick == ""))
  1697.         ondblclick = "slr";
  1698.     
  1699.     if (ondblclick == "")
  1700.         return true;
  1701.     
  1702.     var cancel_click = false;
  1703.  
  1704.     if (ondblclick == "stumble_thru")
  1705.         cancel_click = su_process_stumblethru_click(event);
  1706.     else if(ondblclick == "whitelist_stumbleupon_with_noscript")
  1707.     {
  1708.         var tld = su_get_tld(current_page);
  1709.         if (tld == su_servername)
  1710.         {
  1711.             su_update_noscript_whitelists();
  1712.             cancel_click = true;
  1713.             
  1714.             var ps = su_get_service(
  1715.                         "@mozilla.org/embedcomp/prompt-service;1",
  1716.                         "nsIPromptService");
  1717.             
  1718.             ps.alert(window, "StumbleUpon", "NoScript configuration updated.  You may need to refresh the page or try the operation again.");
  1719.         }
  1720.     }
  1721.     else
  1722.         su_process_slstats_click(event, current_page, ondblclick, ((slq) ? slq : null));
  1723.     
  1724.     if (cancel_click)
  1725.         return su_cancel_event(event);
  1726.     
  1727.     return true;
  1728. }
  1729.  
  1730. function su_process_stumblethru_click(event)
  1731. {
  1732.     var target_anchor = su_get_target_anchor(event.originalTarget, 5);
  1733.     
  1734.     if (! target_anchor)
  1735.         return false;
  1736.     
  1737.     var target = target_anchor.getAttribute("href").toLowerCase();
  1738.     
  1739.     if (target.indexOf("http://www." + su_servername + "/through.php?") != 0)
  1740.         return false;
  1741.     //!!! add stumblevideo case
  1742.  
  1743.     var through_match = target.match(/^http:\/\/[^\/]*\/through.php\?(.+)/);
  1744.     
  1745.     if (! through_match)
  1746.         return false;
  1747.     
  1748.     if (! through_match.length >= 2)
  1749.         return false;
  1750.     
  1751.     if (! su_ds.getValue("@toolbar-visible"))
  1752.         su_toggle_toolbar();
  1753.     
  1754.     // parse out arguments            
  1755.     var spliturl = through_match[1].split("&");
  1756.     
  1757.     su_process_stumble_now(spliturl)
  1758. }
  1759.  
  1760. function su_process_stumble_now(args)
  1761. {
  1762.     var topic_function = "";
  1763.     var topic_displayed = "";
  1764.  
  1765.     var mode = "";
  1766.     var tag = "";
  1767.     var user = "";
  1768.     var topic = "";
  1769.     
  1770.     for (var i = 0; i < args.length; i++)
  1771.     {
  1772.         var thearg = args[i];
  1773.         var argsplit = thearg.split("=");
  1774.         if (argsplit.length > 1)
  1775.         {
  1776.             var key = decodeURIComponent(argsplit[0]);
  1777.             var value = decodeURIComponent(argsplit[1]);
  1778.     
  1779.             if (key == "mode")
  1780.                 mode = value;
  1781.             else if (key == "tag")
  1782.                 tag = value;
  1783.             else if (key == "user")
  1784.                 user = value;                                         
  1785.             else if (key == "topic")
  1786.                 topic = value;
  1787.         }
  1788.     }
  1789.     
  1790.     if (mode == "")
  1791.         return false;
  1792.     
  1793. //                        alert("MODE " + mode + " TAG " + tag + " USER " + user + " TOPIC " + topic);    
  1794.     // we have something    
  1795.     // news, all, tag, video, wiki, photo, language, incat    
  1796.  
  1797.     su_unfocus_searchbox(); 
  1798.     
  1799.     // put it in the box
  1800.     su_get_element("su_searchbox").value=tag;
  1801.     su_get_element("su_searchbox").removeAttribute("mode");
  1802.     su_old_search = tag;
  1803.     su_last_typed_tag = 0;
  1804.     su_visited_searchbox = 1;
  1805.  
  1806.     var category;
  1807.     var label;
  1808.     // select and do it
  1809.     if (mode == "all")
  1810.     {
  1811.         category = 0;
  1812.         label = "All";
  1813.     }
  1814.     else if (mode == "news")
  1815.     {
  1816.         //!!! tagged news?
  1817.         category = "news";
  1818.         label = "News";
  1819.     }
  1820.     else if (mode == "tag" && tag != "")
  1821.     {
  1822.         category = "TAG_" + tag;
  1823.         label = tag;
  1824.     }
  1825.     else if (mode == "user" && user != "" && tag == "")
  1826.     {
  1827.         category = user;
  1828.         label = user;
  1829.     }
  1830.     else if (mode == "user" && user != "" && tag != "")
  1831.     {
  1832.             //!!!!!????
  1833.         category = "USERTAG_" + user + "_" + tag;
  1834.         label = user;
  1835.     }
  1836.     else if (mode == "subscriptions")
  1837.     {
  1838.         category = 'friends';
  1839.         label = 'Stumblers';
  1840.     }
  1841.     else if (mode == "incat" && topic != "")
  1842.     {
  1843.         category = topic;
  1844.         label = su_catnames[topic];
  1845.         if(!label)
  1846.         {
  1847.             // Check for a tag as a backup when the topic id does not exist.
  1848.             if(tag)
  1849.             {
  1850.                 category = "TAG_" + tag;
  1851.                 label = tag;
  1852.             }
  1853.             else
  1854.             {
  1855.                 su_set_location("http://www." + su_servername + "/tag/");
  1856.                 return true;
  1857.             }
  1858.         }
  1859.     }
  1860.     
  1861.     setTimeout(su_select_topic, 0, category, label, false);
  1862.     return true;
  1863. }
  1864.  
  1865. function su_process_slstats_click(event, current_page, ondblclick, slq)
  1866. {
  1867.     var target_anchor = su_get_target_anchor(event.originalTarget, 5);
  1868.     if (! target_anchor)
  1869.         return;
  1870.  
  1871.     if ((! su_host.sha1) || (! su_ds.getValue("@enable_slstats")))
  1872.         return;
  1873.     
  1874.     var sldetail = su_get_search_query_detail(null, current_page);
  1875.     su_ds.setValue("#sldetail", sldetail); 
  1876.     sldetail.target = target_anchor.getAttribute("href");
  1877.     var slt;
  1878.     if (target_anchor.hasAttribute("slt"))
  1879.         slt = target_anchor.getAttribute("slt");
  1880.     else if (slq)
  1881.         slt = "" + slq + su_service.getSha1(target_anchor.getAttribute("href"));
  1882.     
  1883.     if (! slt)
  1884.         return;
  1885.     
  1886.     if (typeof(su_ds.globals.sltih[slt]) == "undefined")
  1887.         return;
  1888.  
  1889.     var row;
  1890.     var sli = su_ds.globals.sltih[slt];
  1891.     var new_row;
  1892.     if (typeof(sli.rowid) != "undefined")
  1893.     {
  1894.         new_row = false;
  1895.         row = su_ds.selectRow("slclick", "_r", sli.rowid);
  1896.     }
  1897.     else if (sli.detail)
  1898.     {
  1899.         new_row = true;
  1900.         row = sli.detail;
  1901.     }
  1902.     else
  1903.     {
  1904.         new_row = true;
  1905.         row = new Object();
  1906.         row.q = slq;
  1907.         row.i = sli.i;
  1908.     }
  1909.     
  1910.     switch (ondblclick)
  1911.     {
  1912.         case "slp":
  1913.             row.p = 1;
  1914.             break;
  1915.         case "sln":
  1916.             row.n = 1;
  1917.             break;
  1918.         case "slu":
  1919.             row.u = 1;
  1920.             break;
  1921.         case "slz":
  1922.             row.z = 1;
  1923.             break;
  1924.         case "slr":
  1925.             row.r = 1;
  1926.             break;
  1927.     }
  1928.     
  1929.     if (new_row)
  1930.         sli.rowid = su_ds.insertRow("slclick", row);
  1931.     else
  1932.         su_ds.updateRow(row);
  1933.     
  1934.     return;
  1935. }
  1936.  
  1937. function su_check_progress_listener()
  1938. {
  1939.     // Check whether the datastore object has buffered any errors.
  1940.     setTimeout(function (win) { win.su_log_error(); }, 0, window);
  1941.     
  1942.     //!!! we have to keep doing this contantly because firefox likes to randomly
  1943.     // drop our addprogresslisteners.  sad but true.
  1944.     
  1945.     // I think the progresslistener gets added to whichever browser
  1946.     // currently has focus in the tabbrowser.  When a browser goes away,
  1947.     // our listener disappears. -- JW 
  1948.     
  1949.     getBrowser().removeProgressListener(su_downloadProgressListener);
  1950.     getBrowser().addProgressListener(su_downloadProgressListener);
  1951.  
  1952.     // for instances where we still need a load listener ( such as interests_after.php )
  1953.     // we can keep call this without removing it, that is part of the DOM spec
  1954.     window.addEventListener("DOMContentLoaded", su_on_load_page, true);
  1955. }
  1956.  
  1957. function su_add_progress_listener()
  1958. {
  1959.     // We need this listener if we have tabs open
  1960.     getBrowser().addProgressListener(su_downloadProgressListener);
  1961. }
  1962.  
  1963. //************** END INITIALIZATION ****************/
  1964.  
  1965. //************** MODEL FUNCTIONS *******************/
  1966.  
  1967. function su_set_legacy_user_interests(str)
  1968. {
  1969.     var blah3 = str.split("|");
  1970.     var blah4 = blah3[1];
  1971.     var blah5 = blah4.split(" ");
  1972.     su_user_interests = new Array();
  1973.     for (var i = 0; i < blah5.length; i++)
  1974.     {
  1975.         if (blah5[i] != "")
  1976.             su_user_interests[blah5[i]] = 1;
  1977.     }
  1978. }
  1979.  
  1980. function su_set_user_interests(str)
  1981. {
  1982.     var parts = str.split(" ");
  1983.     var i;
  1984.     su_user_interests = new Array();
  1985.     for (i = 0; i < parts.length; i++)
  1986.     {
  1987.         if (parts[i] == "")
  1988.             continue;
  1989.         
  1990.         if (! parseInt(parts[i]))
  1991.             continue;
  1992.         
  1993.         su_user_interests[parts[i]] = 1;
  1994.     }
  1995. }
  1996.  
  1997. function su_store_user_interests()
  1998. {
  1999.     var towrite = "";
  2000.     var first = 0;
  2001.     for (var ii in su_user_interests)
  2002.     {
  2003.         if (su_is_property_garbage(su_user_interests, ii))
  2004.             continue;
  2005.         
  2006.         if (first == 0)
  2007.             first = 1;
  2008.         else
  2009.             towrite += " ";
  2010.         towrite += ii + " ";
  2011.     }
  2012.     su_ds.setValue("$interests", towrite);
  2013.     su_ds.flushPrefs();
  2014. }
  2015.  
  2016. function su_legacy_interests_after_page(doc)
  2017. {
  2018.     var el = doc.getElementById("interests");
  2019.     if (! el)
  2020.         return;
  2021.     
  2022.     su_set_legacy_user_interests(el.innerHTML);
  2023.     su_store_user_interests();
  2024.     
  2025.     su_refresh_category_selector_batched();
  2026.     
  2027.     clear_stumbles();
  2028. }
  2029.  
  2030. function su_interests_page(doc)
  2031. {
  2032.     var el = doc.getElementById("topic_list");
  2033.  
  2034.     if (! el)
  2035.         return;
  2036.     
  2037.     su_process_topic_list(el.innerHTML);
  2038. }
  2039.  
  2040. function su_prefs_page(doc)
  2041. {
  2042.     var el;
  2043.     
  2044.     el = doc.getElementById("changePassword");
  2045.     
  2046.     if (! el)
  2047.         return;
  2048.     
  2049.     try {
  2050.         el.wrappedJSObject.addEventListener(
  2051.                 "click",
  2052.                 su_handle_change_password,
  2053.                 false);
  2054.     } catch (e) {}
  2055. }
  2056.  
  2057. function su_tag_page(doc)
  2058. {
  2059.     var el;
  2060.     
  2061.     el = doc.getElementById("thumbup");
  2062.     if (el)
  2063.     {
  2064.         try {
  2065.             el.wrappedJSObject.addEventListener(
  2066.                     "click",
  2067.                     su_handle_interests_change_click,
  2068.                     false);
  2069.         } catch (e) {}
  2070.     }
  2071.     
  2072.     el = doc.getElementById("thumbdown");
  2073.     if (el)
  2074.     {
  2075.         try {
  2076.             el.wrappedJSObject.addEventListener(
  2077.                     "click",
  2078.                     su_handle_interests_change_click,
  2079.                     false);
  2080.         } catch (e) {}
  2081.     }
  2082. }
  2083.  
  2084. function su_handle_interests_change_click()
  2085. {
  2086.     setTimeout(su_get_interests, 1000);
  2087.     setTimeout(su_get_interests, 8000);
  2088. }
  2089.  
  2090. function su_portal_http_page(doc)
  2091. {
  2092.     var el = doc.getElementById("topic_list");
  2093.     
  2094.     if (! el)
  2095.         return;
  2096.     
  2097.     su_process_topic_list(el.innerHTML);
  2098. }
  2099.  
  2100. function su_process_topic_list(str)
  2101. {
  2102.     if (str == su_ds.getValue("#prev_topic_list"))
  2103.         return;
  2104.         
  2105.     su_ds.setValue("#prev_topic_list", str);
  2106.  
  2107.     su_set_user_interests(str);
  2108.     su_store_user_interests();
  2109.     
  2110.     su_refresh_category_selector_batched();
  2111.     clear_stumbles();
  2112. }
  2113.  
  2114. //
  2115. // su_update_topic_list
  2116. //
  2117. // This is the same as su_process_topic_list, except it isn't restricted
  2118. // to only running once per session with #prev_topic_list.  To be honest,
  2119. // I'm not sure why that is required, so I've created a new command so
  2120. // topic updates can be driven by the web page via. the suLitebarApi.
  2121. //
  2122. function su_update_topic_list(str)
  2123. {
  2124.     su_set_user_interests(str);
  2125.     su_store_user_interests();
  2126.     
  2127.     su_refresh_category_selector_batched();
  2128.     clear_stumbles();
  2129. }
  2130.  
  2131. function su_process_friends_command(command_str)
  2132. {
  2133.     if (command_str == su_ds.getValue("#prev_friends"))
  2134.         return;
  2135.     
  2136.     if (su_ds.getValue("#installing_all_avatars"))
  2137.         return;
  2138.  
  2139.     su_ds.setValue("#prev_friends", command_str);
  2140.     
  2141.     var friends = command_str.split(" ");
  2142.     friends.shift();
  2143.     
  2144.     if(friends.length)
  2145.     {
  2146.         // If they have friends, then show the friends menu.
  2147.         if(!su_ds.getValue("$show_friends_user_changed"))
  2148.         {
  2149.             su_ds.setValue("$show_friends", true);
  2150.             su_set_visible("su_friends", true);
  2151.         }
  2152.     }
  2153.     
  2154.     var i;
  2155.     var contact;
  2156.     var mutuals = new Object();
  2157.     var changed = false;
  2158.     var has_avatars = su_ds.getValue("$has_avatars");
  2159.     if (! has_avatars)
  2160.         su_ds.setValue("#installing_all_avatars", true);
  2161.     var contacts = su_ds.selectAllRows("contact");
  2162.     var new_contacts = new Array();
  2163.     var contacts_by_id = new Object();
  2164.     for (i = 0; i < contacts.length; i++)
  2165.     {
  2166.         if (contacts[i].contactid)
  2167.             contacts_by_id[contacts[i].contactid] = contacts[i];
  2168.     }
  2169.     
  2170.     for (i = 0; i < friends.length; i++)
  2171.     {
  2172.         var nickname = friends[i].split(".")[0];
  2173.         var contactid = friends[i].split(".")[1];
  2174.         mutuals[contactid] = true;
  2175.         
  2176.         contact = null;
  2177.         
  2178.         if (contacts_by_id[contactid])
  2179.             contact = contacts_by_id[contactid];
  2180.             
  2181.         if (contact)
  2182.         {
  2183.             contacts_by_id[contact.contactid] = null;
  2184.             if (contact.contactid != contactid)
  2185.             {
  2186.                 changed = true;
  2187.                 contact.contactid = contactid;
  2188.             }
  2189.             if (contact.nickname != nickname)
  2190.             {
  2191.                 changed = true;
  2192.                 contact.nickname = nickname;
  2193.             }
  2194.             if (! contact.mutual)
  2195.             {
  2196.                 changed = true;
  2197.                 contact.mutual = 1;
  2198.             }
  2199.             if (changed)
  2200.                 su_ds.updateRow(contact);
  2201.             if (! has_avatars)
  2202.                 su_ds.refreshAvatar(contactid);
  2203.             contacts_by_id[contactid] = contact;
  2204.         }
  2205.         else
  2206.         {
  2207.             changed = true;
  2208.             contact = new Object();
  2209.             contact.contactid = contactid;
  2210.             contact.nickname = nickname;
  2211.             contact.mutual = 1;
  2212.             su_ds.refreshAvatar(contactid);
  2213.             su_ds.insertRow("contact", contact);
  2214.             contacts_by_id[contactid] = contact;
  2215.         }
  2216.     }
  2217.  
  2218.     for (i = 0; i < contacts.length; i++)
  2219.     {
  2220.         if ((typeof (contacts[i])) == "undefined")
  2221.         {
  2222.             su_log_error("LEGACY FRIENDS");
  2223.             contacts.splice(i, 1);
  2224.             i--;
  2225.             continue;
  2226.         }
  2227.         
  2228.         if ((typeof (contacts[i].contactid)) != "undefined")
  2229.         {
  2230.             if (! mutuals[contacts[i].contactid])
  2231.             {
  2232.                 if (contacts[i].mutual)
  2233.                 {
  2234.                     changed = true;
  2235.                     contacts[i].mutual = 0;
  2236.                     su_ds.updateRow(contacts[i]);
  2237.                 }
  2238.             }
  2239.         }
  2240.     }
  2241.     
  2242.     if (changed)
  2243.         su_refresh_referral_menu(1);
  2244. }
  2245.  
  2246. /*
  2247. function su_process_fbfriends_command(command_str)
  2248. {
  2249.     var friends = command_str.split(" ");
  2250.     friends.shift();
  2251.     
  2252.     var i;
  2253.     var contact;
  2254.     var contacts = su_ds.selectAllRows("contact");
  2255.     var contacts_by_id = new Object();
  2256.     var fbfriends = new Object();
  2257.     for (i = 0; i < contacts.length; i++)
  2258.     {
  2259.         if (contacts[i].contactid)
  2260.             contacts_by_id[contacts[i].contactid] = contacts[i];
  2261.     }
  2262.     
  2263.     for (i = 0; i < friends.length; i++)
  2264.     {
  2265.         var contactid = friends[i].split(".")[0];
  2266.         var nickname = friends[i].split(".")[1];
  2267.         var facebookid = friends[i].split(".")[2];
  2268.         
  2269.         fbfriends[contactid] = true;
  2270.  
  2271.         contact = null;
  2272.         
  2273.         if (contacts_by_id[contactid])
  2274.             contact = contacts_by_id[contactid];
  2275.         
  2276.         if (contact)
  2277.         {
  2278.             contact.nickname = nickname;
  2279.             contact.fbid = facebookid;
  2280.             su_ds.updateRow(contact);
  2281.         }
  2282.         else
  2283.         {
  2284.             contact = new Object();
  2285.             contact.contactid = contactid;
  2286.             contact.nickname = nickname;
  2287.             contact.fbid = facebookid;
  2288.             su_ds.insertRow("contact", contact);
  2289.             contacts_by_id[contactid] = contact;
  2290.         }
  2291.     }
  2292.  
  2293.     for (i = 0; i < contacts.length; i++)
  2294.     {
  2295.         if ((typeof (contacts[i].contactid)) != "undefined")
  2296.         {
  2297.             if (contacts[i].fbid && (! fbfriends[contacts[i].contactid]))
  2298.                 contacts[i].fbid = 0;
  2299.             
  2300.             su_ds.updateRow(contacts[i]);
  2301.         }
  2302.     }
  2303. }
  2304. */
  2305.  
  2306. //************** END MODEL FUNCTIONS ***************/
  2307.  
  2308.  
  2309.  
  2310. //************** UTILITY FUNCTIONS *****************/
  2311.  
  2312. // See global.js for additional utility functions.
  2313.  
  2314. function su_is_matching_domain(uri, domain, opt_parts_length_offset)
  2315. {
  2316.     var splituri = uri.split("/");
  2317.     
  2318.     if (splituri.length < 3)
  2319.         return false;
  2320.  
  2321.     var uri_domains = splituri[2].split(".");
  2322.     var ref_domains = domain.split(".");
  2323.     
  2324.     if ((typeof(opt_parts_length_offset) != "undefined") &&
  2325.                 (uri_domains.length - ref_domains.length) != opt_parts_length_offset)
  2326.         return false;
  2327.         
  2328.     else if (uri_domains.length < ref_domains.length)
  2329.         return false;
  2330.  
  2331.     var i = ref_domains.length-1;
  2332.     var j = uri_domains.length-1;
  2333.     while (i >= 0)
  2334.     {
  2335.         if (uri_domains[j] != ref_domains[i])
  2336.             return false;
  2337.         i--;
  2338.         j--;
  2339.     }
  2340.     return true;
  2341. }
  2342.  
  2343. function su_get_domain(opt_url)
  2344. {
  2345.     var url;
  2346.     if (opt_url)
  2347.         url = opt_url;
  2348.     else
  2349.         url = su_get_browser_url();
  2350.     
  2351.     var url_parts = url.split("/");
  2352.     
  2353.     if (url_parts.length < 3)
  2354.         return "";
  2355.     
  2356.     return url_parts[2];
  2357. }
  2358.  
  2359. function su_normalize_tag(str)
  2360. {
  2361.     str = str.replace(/\s+/g, " ");
  2362.     str = str.replace(/\s*,+\s*/g, ", ");
  2363.     str = str.replace(/^,/, "");
  2364.     str = str.replace(/,\s$/, "");
  2365.     return str;
  2366. }
  2367.  
  2368. function su_is_sound(url)
  2369. {
  2370.     // checks to see if url produces sound
  2371.     var last3 = url.substr(url.length-3).toLowerCase();
  2372.     var last4 = url.substr(url.length-4).toLowerCase();
  2373.     var last5 = url.substr(url.length-5).toLowerCase();
  2374.     if (    last3 == ".qt" || last3 == ".ra" || last3 == ".rm" 
  2375.         || last3 == ".rv" || last3 == ".au" || last3 == ".ul"
  2376.           || last4 == ".avi" || last4 == ".asf" || last4 == ".mpg"
  2377.            || last4 == ".wmf" || last4 == ".wmv" || last4 == ".wma"
  2378.         || last4 == ".wav" || last4 == ".mov" || last4 == ".mp3"
  2379.         || last4 == ".ram" || last4 == ".swf" || last4 == ".mp4"
  2380.         || last4 == ".mpe" || last4 == ".mpv" || last4 == ".mp2"
  2381.         || last4 == ".aac" || last4 == ".aif" || last4 == ".mid" 
  2382.         || last4 == ".ogg" || last4 == ".ogm" || last4 == ".ac3" 
  2383.         || last4 == ".fla" || last4 == ".awm" || last4 == ".ftk"
  2384.         || last4 == ".mod" || last4 == ".sid" || last4 == ".nap"
  2385.         || last4 == ".mmm"
  2386.         || last5 == ".aiff"
  2387.         || last5 == ".midi"
  2388.         || last5 == ".mpeg")
  2389.     {
  2390.         return 1;
  2391.     }
  2392.     else
  2393.     {
  2394.         return 0;
  2395.     }
  2396. }
  2397.  
  2398. function su_is_url_rateable(url, tld)
  2399. {
  2400.     // Not enabled for about:, mailto:, etc.
  2401.     if (!url.match(/^(http|https|ftp):/i))
  2402.         return false;
  2403.  
  2404.     // Not enabled for url pages
  2405.     
  2406.     if (url.indexOf(su_base_url + "url/") == 0 || url.indexOf(su_base_url + "url.php") == 0)
  2407.         return false;
  2408.     
  2409.     if (url == "http://video." + su_servername + "/")
  2410.         return false;
  2411.     
  2412.     if (tld)
  2413.         return true;
  2414.     
  2415.     return false;
  2416. }
  2417.  
  2418. function su_is_adult_category(cat)
  2419. {
  2420.     if (cat == null)
  2421.         return false;
  2422.     
  2423.     cat += "";
  2424.     
  2425.     switch (cat)
  2426.     {
  2427.         case "6":    //  Pornography
  2428.         case "159":  //  Fetish Sexuality
  2429.         case "193":  //  Hentai Anime
  2430.         case "510":  //  Gay Sex
  2431.         case "513":  //  Lesbian Sex
  2432.         case "521":  //  BDSM
  2433.         case "522":  //  Bisexual Sex
  2434.         case "531":  //  Transexual Sex
  2435.             return true;
  2436.             break;
  2437.     }
  2438.     return false;
  2439. }
  2440.  
  2441. function su_get_media_specs()
  2442. {
  2443.     var specs = new Array();
  2444.     var collection;
  2445.     var i;
  2446.     var doc = getBrowser().contentDocument;
  2447.     
  2448.     collection = doc.getElementsByTagName("EMBED");
  2449.     for (i = 0; i < collection.length; i++)
  2450.         specs.push(su_get_media_spec(collection[i]));
  2451.     
  2452.     collection = doc.getElementsByTagName("OBJECT");
  2453.     for (i = 0; i < collection.length; i++)
  2454.         specs.push(su_get_media_spec(collection[i]));
  2455.     
  2456.     collection = doc.getElementsByTagName("APPLET");
  2457.     for (i = 0; i < collection.length; i++)
  2458.         specs.push(su_get_media_spec(collection[i]));
  2459.     
  2460.     collection = doc.getElementsByTagName("img");
  2461.     for (i = 0; i < collection.length; i++)
  2462.     {
  2463.         var spec = su_get_media_spec(collection[i]);
  2464.         if (spec)
  2465.             specs.push(spec);
  2466.     }
  2467.  
  2468.     return specs;
  2469. }
  2470.  
  2471. function su_get_media_spec(el)
  2472. {
  2473.     var spec = su_get_property_map(el);
  2474.     
  2475.     spec.tagName = el.tagName.toLowerCase();
  2476.  
  2477.     if (el.boxObject)
  2478.     {
  2479.         spec.width = el.boxObject.width;
  2480.         spec.height = el.boxObject.height;
  2481.         spec.top = el.boxObject.top;
  2482.     }
  2483.     else
  2484.     {
  2485.         spec.width = 0;
  2486.         spec.height = 0;
  2487.         spec.top = 0;
  2488.     }
  2489.  
  2490.     if (spec.tagName == "img")
  2491.     {
  2492.         var area = spec.width * spec.height;
  2493.         if (area > 70000)
  2494.             return spec;
  2495.         else
  2496.             return null;
  2497.     }
  2498.  
  2499.     if (spec.type)
  2500.         return spec;
  2501.     
  2502.     if ((spec.tagName == "applet") || 
  2503.                 (spec.code && (spec.code.indexOf(".class") != -1)))
  2504.         spec.type = "application/x-java-applet";
  2505.  
  2506.     else if ((spec.src && (spec.src.indexOf(".swf") != -1)) || 
  2507.                 (spec.movie && (spec.movie.indexOf(".swf") != -1)))
  2508.         spec.type = "application/x-shockwave-flash";
  2509.  
  2510.     return spec;
  2511. }
  2512.  
  2513. function su_get_property_map(el)
  2514. {
  2515.     var map = new Object();
  2516.     var i;
  2517.     for (i = 0; i < el.attributes.length; i++)
  2518.     {
  2519.         // Add properties representing attributes. -- JW
  2520.         map[el.attributes.item(i).nodeName.toLowerCase()] = el.attributes.item(i).nodeValue;
  2521.     }
  2522.     
  2523.     var children = el.childNodes;
  2524.     for (i = 0; i < children.length; i++)
  2525.     {
  2526.         // Add properties representing param entities. -- JW
  2527.         if (children[i].tagName != "PARAM")
  2528.             continue;
  2529.         
  2530.         if (children[i].hasAttribute("name") && children[i].hasAttribute("value"))
  2531.             map[children[i].getAttribute("name").toLowerCase()] = children[i].getAttribute("value");
  2532.     }
  2533.     return map;
  2534. }
  2535.  
  2536. function su_get_target_anchor(el, search_depth)
  2537. {
  2538.     var found_el = null;
  2539.     var i;
  2540.     for (i = 0; i < search_depth; i++)
  2541.     {
  2542.         if (el.tagName && (el.tagName == "A"))
  2543.         {
  2544.             found_el = el;
  2545.             break;
  2546.         }
  2547.         if (el.parentNode)
  2548.             el = el.parentNode;
  2549.         else
  2550.             break;
  2551.     }
  2552.     return found_el;
  2553. }
  2554.  
  2555. function su_get_ancestor_by_prop_value(el, prop_name, prop_value, search_depth)
  2556. {
  2557.     var found_el = null;
  2558.     var i;
  2559.     for (i = 0; i < search_depth; i++)
  2560.     {
  2561.         if (el.parentNode)
  2562.             el = el.parentNode;
  2563.         else
  2564.             break;
  2565.         
  2566.         if (el[prop_name] == prop_value)
  2567.         {
  2568.             found_el = el;
  2569.             break;
  2570.         }
  2571.     }
  2572.     return found_el;
  2573. }
  2574.  
  2575. function su_is_mutual_friend(nickname)
  2576. {
  2577.     if (! nickname)
  2578.         return false;
  2579.     
  2580.     nickname += "";
  2581.     
  2582.     if (nickname == "")
  2583.         return false;
  2584.     
  2585.     var query = nickname.toLowerCase();
  2586.     
  2587.     var contacts = su_ds.selectAllRows("contact");
  2588.     var found = false;
  2589.     var i;
  2590.     for (i = 0; i < contacts.length; i++)
  2591.     {
  2592.         if ((contacts[i].nickname) && 
  2593.                     (contacts[i].mutual) &&
  2594.                     (contacts[i].nickname.toLowerCase() == query))
  2595.         {
  2596.             found = true;
  2597.             break;
  2598.         }
  2599.     }
  2600.     
  2601.     return found;
  2602. }
  2603.  
  2604. function su_prefix_article(str)
  2605. {
  2606.     if (! str)
  2607.         return "";
  2608.     
  2609.     if (str == "")
  2610.         return "";
  2611.     
  2612.     var chr = str.charAt(0).toLowerCase();
  2613.     
  2614.     var article;
  2615.     switch (chr)
  2616.     {
  2617.         case "a":
  2618.         case "e":
  2619.         case "i":
  2620.         case "o":
  2621.         case "u":
  2622.             article = "an";
  2623.             break;
  2624.         default:
  2625.             article = "a";
  2626.             break;
  2627.     }
  2628.     
  2629.     return article + " " + str;
  2630. }
  2631.  
  2632. function su_new_tab(event)
  2633. {
  2634.     if (! event)
  2635.         return false;
  2636.     
  2637.     var platform_ctrl_key = (su_host.mac) ? event.metaKey : event.ctrlKey;
  2638.     var new_tab = false;
  2639.     if (event.button == 1 || (event.button == 0 && platform_ctrl_key))
  2640.         new_tab = true;
  2641.     return new_tab;
  2642. }
  2643.  
  2644. function su_is_about_blank()
  2645. {
  2646.     var doc = getBrowser().contentDocument;
  2647.     if(doc && (doc.location.toString() == "about:blank"))
  2648.         return true;
  2649.     else
  2650.         return false;
  2651. }    
  2652.         
  2653. function su_cancel_event(event)
  2654. {
  2655.     event.stopPropagation();
  2656.     if (event.cancelable)
  2657.         event.preventDefault();            
  2658.     event.cancelBubble = true;
  2659.     return false;
  2660. }
  2661.  
  2662. // returns the number of browser windows
  2663. function su_get_browser_window_count()
  2664. {
  2665.     var enumerator = su_get_service(
  2666.                 "@mozilla.org/appshell/window-mediator;1",
  2667.                 "nsIWindowMediator")
  2668.                 .getEnumerator("navigator:browser");
  2669.     
  2670.     var count = 0;
  2671.     while (enumerator.hasMoreElements())
  2672.     {
  2673.         count++;
  2674.         enumerator.getNext();
  2675.     }
  2676.     return count;
  2677. }
  2678.  
  2679. function su_get_rdf_resource(resource_id)
  2680. {
  2681.     return su_get_service(
  2682.                 "@mozilla.org/rdf/rdf-service;1",
  2683.                 "nsIRDFService")
  2684.                 .GetResource(resource_id)
  2685.                 .QueryInterface(Components.interfaces.nsIRDFResource)
  2686. }
  2687.  
  2688. function su_get_rdf_arc_literal(datasource, element, arc_id)
  2689. {
  2690.     try {
  2691.         var arc = su_get_rdf_resource(arc_id);
  2692.                     
  2693.         element.QueryInterface(Components.interfaces.nsIRDFResource);
  2694.         
  2695.         var target = datasource.GetTarget(element, arc ,true);
  2696.         if (target)
  2697.             return target.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
  2698.     } catch (e) {}
  2699.     return null;
  2700. }
  2701.  
  2702. function su_get_rdf_arc_int(datasource, element, arc_id)
  2703. {
  2704.     try {
  2705.         var arc = su_get_rdf_resource(arc_id);
  2706.                     
  2707.         element.QueryInterface(Components.interfaces.nsIRDFResource);
  2708.         
  2709.         var target = datasource.GetTarget(element, arc ,true);
  2710.         if (target)
  2711.             return target.QueryInterface(Components.interfaces.nsIRDFInt).Value;
  2712.     } catch (e) {}
  2713.     return null;
  2714. }
  2715.  
  2716. // returns a mime input stream, used primarily for wrapping POST data
  2717. function su_get_mime_input_stream(str, content_type)
  2718. {
  2719.   var data_stream = su_create_instance(
  2720.                 "@mozilla.org/io/string-input-stream;1",
  2721.                 "nsIStringInputStream");
  2722.   data_stream.setData(str, str.length);
  2723.  
  2724.   var mime_stream = su_create_instance(
  2725.                 "@mozilla.org/network/mime-input-stream;1",
  2726.                 "nsIMIMEInputStream");
  2727.   mime_stream.addHeader("Content-Type", content_type);
  2728.   mime_stream.addContentLength = true;
  2729.   mime_stream.setData(data_stream);
  2730.   return mime_stream.QueryInterface(Components.interfaces.nsIInputStream);
  2731. }
  2732.  
  2733. function su_get_browser_url(opt_doc, opt_raw)
  2734. {
  2735.     var doc = (opt_doc) ? opt_doc : getBrowser().contentDocument;
  2736.     var url = doc.location.toString();
  2737.     if (url.indexOf("chrome://ietab/content/reloaded.html?url=") == 0)
  2738.         url = url.substr(41);
  2739.     
  2740.     if (opt_raw)
  2741.         return url;
  2742.     
  2743.     if (su_is_matching_domain(url, "video." + su_servername))
  2744.     {
  2745.         var detail = su_get_stumblevideo_detail(doc);
  2746.         if (detail)
  2747.             url = detail.url;
  2748.     }
  2749.     
  2750.     return url;
  2751. }
  2752.  
  2753. function su_get_browser_referrer_url(opt_doc, opt_raw)
  2754. {
  2755.     var doc = (opt_doc) ? opt_doc : getBrowser().contentDocument;
  2756.     var url = doc.referrer.toString();
  2757.     if (url.indexOf("chrome://ietab/content/reloaded.html?url=") == 0)
  2758.         url = url.substr(41);
  2759.     
  2760.     if (opt_raw)
  2761.         return url;
  2762.     
  2763. //    if (su_is_matching_domain(url, "video." + su_servername))
  2764. //    {
  2765. //        var detail = su_get_stumblevideo_detail(doc);
  2766. //        if (detail)
  2767. //            url = detail.url;
  2768. //    }
  2769.     
  2770.     return url;
  2771. }
  2772.  
  2773. function su_dispatch_click(doc, id)
  2774. {
  2775.     var el = doc.getElementById(id);
  2776.     if (! el)
  2777.         return;
  2778.  
  2779.     var evt = doc.createEvent("MouseEvent");
  2780.     evt.initMouseEvent(
  2781.                 "click",
  2782.                 true,
  2783.                 true,
  2784.                 doc.defaultView,
  2785.                 1,
  2786.                 0, // screenX
  2787.                 0, // screenY
  2788.                 0, // clientX
  2789.                 0, // clientY
  2790.                 false,
  2791.                 false,
  2792.                 false,
  2793.                 false,
  2794.                 0,
  2795.                 null);
  2796.     el.dispatchEvent(evt);
  2797. }
  2798.  
  2799. /*
  2800. function su_dispatch_mouseover(doc, id)
  2801. {
  2802.     var el = doc.getElementById(id);
  2803.     if (! el)
  2804.         return;
  2805.  
  2806.     var evt = doc.createEvent("MouseEvent");
  2807.     evt.initMouseEvent(
  2808.                 "mouseover",
  2809.                 true,
  2810.                 true,
  2811.                 doc.defaultView,
  2812.                 1,
  2813.                 0, // screenX
  2814.                 0, // screenY
  2815.                 0, // clientX
  2816.                 0, // clientY
  2817.                 false,
  2818.                 false,
  2819.                 false,
  2820.                 false,
  2821.                 0,
  2822.                 null);
  2823.     el.dispatchEvent(evt);
  2824. }
  2825. */
  2826.  
  2827. const su_DEBUG_ENABLED = true;
  2828.  
  2829. /*
  2830. function su_insert_before(parent, new_el, after_el)
  2831. {
  2832.     if (parent && after_el && after_el.parentNode && (after_el.parentNode == parent))
  2833.         after_el.insertBefore(new_el, after_el.nextSibling);
  2834.     else if (parent)
  2835.         parent.appendChild(new_el);
  2836. }
  2837. */
  2838.  
  2839. function su_get_element(id)
  2840. {
  2841.     return document.getElementById(id);
  2842. }
  2843.  
  2844. // When doing a 'for ([prop] in [obj])', use this to verify that the
  2845. // property isn't pollution from another extension.
  2846. function su_is_property_garbage(obj, prop)
  2847. {
  2848.     return ((typeof (obj[prop])) == "function");
  2849. }
  2850.  
  2851. function su_invert_dictionary(dict)
  2852. {
  2853.     var out = new Object();
  2854.  
  2855.     var key;
  2856.     for (key in dict)
  2857.     {
  2858.         if (su_is_property_garbage(dict, key))
  2859.             continue;
  2860.         
  2861.         out[dict[key]] = key; 
  2862.     }
  2863.  
  2864.     return out;
  2865. }
  2866.  
  2867. function su_log_dd_uc(unseen)
  2868. {
  2869.     if (    su_ds.lookup("userid:uc_logger_flag", stumbleid) ||
  2870.                 su_ds.getValue("@dd_uc"))
  2871.     {
  2872.         var str = " " + su_ds.getValue("@dd_uc_server") + " " + unseen + "\n";
  2873.         su_ds.writeFile(
  2874.                     su_ds.getLegacyNSIFile("stumbledd"),
  2875.                     (su_ds.getTimestampStr(0) + str),
  2876.                     true);
  2877.         su_ds.writeFile(
  2878.                     su_ds.getLegacyNSIFile("stumbleddw"),
  2879.                     (su_ds.getTimestampStr(1) + str),
  2880.                     true);
  2881.     }
  2882. }
  2883.  
  2884. function su_get_time_s()
  2885. {
  2886.     return Math.floor((new Date()).getTime() / 1000);
  2887. }
  2888.  
  2889. function su_trim(str)
  2890. {
  2891.     return str.replace(/^\s*|\s*$/g,"");
  2892. }
  2893.  
  2894. function su_escape_regexp_chars(str)
  2895. {
  2896.     return str.replace(/([\\\^\*\+\?\.\(\)\|\{\}\[\]])/g, "\\$1");
  2897. }
  2898.  
  2899. function su_clone(obj)
  2900. {
  2901.     return su_ds.deserialize(su_ds.serialize(obj, false));
  2902. }
  2903.  
  2904. // append request param
  2905. function su_arp(param_str, name, value, opt_get_flag)
  2906. {
  2907.     var delimiter;
  2908.     if (opt_get_flag && (param_str.indexOf("&") == -1) &&
  2909.                 (param_str.indexOf("?") == -1))
  2910.         delimiter = "?";
  2911.     else
  2912.         delimiter = "&";
  2913.     
  2914.     return param_str + ((param_str == "") ? "" : delimiter) + name + "=" + 
  2915.                 encodeURIComponent(value);
  2916. }
  2917.  
  2918. function su_build_request_param_string(spec)
  2919. {
  2920.     var str = "";
  2921.     var name;
  2922.     for (name in spec)
  2923.     {
  2924.         if (su_is_property_garbage(spec, name))
  2925.             continue;
  2926.         
  2927.         str += ((str == "") ? "" : "&") + name + "=" + 
  2928.                 encodeURIComponent(spec[name]);
  2929.     }
  2930.     return str;
  2931. }
  2932.  
  2933. function su_create_instance(nsclass, nsinterface)
  2934. {
  2935.     try {
  2936.         return Components.classes[nsclass]
  2937.                     .createInstance(Components.interfaces[nsinterface]);
  2938.     }
  2939.     catch (e) {
  2940.         return null;
  2941.     }
  2942. }
  2943.  
  2944. function su_get_service(nsclass, nsinterface)
  2945. {
  2946.     try {
  2947.         return Components.classes[nsclass]
  2948.                     .getService(Components.interfaces[nsinterface]);
  2949.     }
  2950.     catch (e) {
  2951.         return null;
  2952.     }
  2953. }
  2954.  
  2955. // returns an nsIURI object for the specified uri
  2956. function su_get_nsiuri(uri_str)
  2957. {
  2958.     var uri = su_create_instance(
  2959.                 "@mozilla.org/network/standard-url;1",
  2960.                 "nsIURI");
  2961.     uri.spec = uri_str;
  2962.     return uri;
  2963. }
  2964.  
  2965. // writes all arguments to a console message
  2966. function su_dd()
  2967. {
  2968.     if (! su_DEBUG_ENABLED)
  2969.         return;
  2970.  
  2971.     su_service.dd.apply(su_service, arguments);
  2972. }
  2973.  
  2974. function su_ddf()
  2975. {
  2976.     su_service.ddf.apply(su_service, arguments);
  2977. }
  2978.  
  2979. window.su_log = su_dd;
  2980.  
  2981. window.su_logf = su_ddf;
  2982.  
  2983. // writes all properties of an object to a console message
  2984. function su_dump_object(o)
  2985. {
  2986.     var str = "";
  2987.     var p;
  2988.     
  2989.     for (p in o)
  2990.     {
  2991.         try {
  2992.             str += "[" + p + "]\n" + o[p] + "\n\n";
  2993.         }
  2994.         catch (e) {
  2995.             str += "[" + p + "] ERROR\n" + e + "\n\n";
  2996.         }
  2997.     }
  2998.     su_log(str);
  2999. }
  3000.  
  3001. function su_log_error()
  3002. {
  3003.     if (! su_DEBUG_ENABLED)
  3004.         return;
  3005.  
  3006.     su_service.logError.apply(su_service, arguments);
  3007. }
  3008.  
  3009. // send a notification to the event_observer for each window
  3010. function su_invoke_global_event(event_id, detail, from)
  3011. {
  3012.     if (event_id == "update-referral-menu")
  3013.     {
  3014.         su_ds.flushPrefs();
  3015.     }
  3016.     else if ((event_id == "login") && detail && (! detail.skip_cookies)
  3017.             && detail.ignore_cookies)
  3018.     {
  3019.         su_process_cookies(true);
  3020.         detail.skip_cookies = true;
  3021.     }
  3022.     
  3023.     su_get_service(
  3024.                 "@mozilla.org/observer-service;1",
  3025.                 "nsIObserverService")
  3026.                 .notifyObservers(null, "su_" + event_id, su_ds.serialize(detail));
  3027. }
  3028.  
  3029. //************** END UTILITY FUNCTIONS ***************/
  3030.  
  3031.  
  3032. //******** FILE FUNCTIONS **********//
  3033.  
  3034. //
  3035. // Note:  This code includes the ability to fallback to user prefs for file storage.
  3036. //        But since prefs are written frequently, useFailsafe should NOT be used except
  3037. //        when reading / writing very small files.
  3038. //
  3039. function _su_read_file_user(fname, useFailsafe)
  3040. {
  3041.     // We fall back to using prefs if they have asked for it for this specific
  3042.     // operation, _and_ a previous file write operation failed _and_ the failsafe
  3043.     // option is enabled.
  3044.     //
  3045.     if(useFailsafe &&
  3046.        su_ds.getValue("@userfile_write_failed") &&
  3047.        su_ds.getValue("@enable_userfile_failsafe"))
  3048.     {
  3049.         // A previous write failed, so we are using prefs.
  3050.         var result = su_ds.getPrefValue("$file_" + fname + "_failsafe", "");
  3051.         return result;
  3052.     }
  3053.     else
  3054.     {
  3055.         return su_ds.readFile(su_ds.getLegacyNSIFile(fname));
  3056.     }
  3057. }
  3058.  
  3059. function _su_write_file_user(fname, data, useFailsafe)
  3060. {
  3061.     if(useFailsafe &&
  3062.        su_ds.getValue("@userfile_write_failed") &&
  3063.        su_ds.getValue("@enable_userfile_failsafe"))
  3064.     {
  3065.         // If we have failed writing to the filesystem, then we failover
  3066.         // to using prefs for our user data storage.
  3067.         su_ds.setValue("$file_" + fname + "_failsafe", data);
  3068.         su_ds.flushPrefs();
  3069.     }
  3070.     else
  3071.     {
  3072.         try
  3073.         {
  3074.             // Try the normal file operation.
  3075.             var file = su_ds.getLegacyNSIFile(fname);
  3076.             su_ds.writeFile(file, data);
  3077.             var result = su_ds.readFile(file);
  3078.             if(result != data)
  3079.             {
  3080.                 // This is a ZoneAlarm ForceField hack.  ForceField causes file writes to fail
  3081.                 // silently, so we double-check whether the write succeeded and throw our own error
  3082.                 // on failure.
  3083.                 throw "Data is different";
  3084.             }
  3085.         }
  3086.         catch(ex)
  3087.         {
  3088.             su_log_error("USERFILE FAILURE: " + ex);
  3089.             su_ds.setValue("$file_" + fname + "_failsafe", data);
  3090.             su_ds.setValue("@userfile_write_failed", true);
  3091.             su_ds.flushPrefs();
  3092.         }
  3093.     }
  3094. }
  3095.  
  3096. function su_read_file_user(fname)
  3097. {
  3098.     return _su_read_file_user(fname, fname == "stumbleurls");
  3099. }
  3100.  
  3101. function su_write_file_user(fname, data)
  3102. {
  3103.     _su_write_file_user(fname, data, fname == "stumbleurls");
  3104. }
  3105.         
  3106. //***************** END FILE FUNCTIONS ******************//
  3107.  
  3108.  
  3109. //***************** GUI HANDLERS ************************//
  3110.  
  3111. // deals with interests if you select it from the menu item add more interests...
  3112. function su_interests_pre()
  3113. {
  3114.     su_interests();
  3115.     su_set_mode_all();
  3116. }
  3117.  
  3118.  
  3119. //!!! We probably ought to combine su_handle_mode_click and
  3120. //    su_select_topic, but to mitigate risk, this change is deferred
  3121. //    until after 3.0. -- JW
  3122. function su_handle_mode_click(event, mode)
  3123. {
  3124.     var new_tab = su_new_tab(event);
  3125.     
  3126.     var tag;
  3127.     switch (mode)
  3128.     {
  3129.         case "All":
  3130.             su_select_topic(0, mode, new_tab);
  3131.             break;
  3132.         case "Videos":
  3133.             su_select_topic("video", mode, new_tab);
  3134.             break;
  3135.         case "Photos":
  3136.             su_select_topic(302, mode, new_tab);
  3137.             break;
  3138.         case "Friends":
  3139.             su_select_topic("friends", mode, new_tab);
  3140.             break;
  3141.         case "Profiles":
  3142.             su_select_topic(44, mode, new_tab);
  3143.             break;
  3144.         case "Search":
  3145.             new_tab = new_tab || su_ds.getValue("$search_new_window");
  3146.             setTimeout(su_show_search_dialog, 0, new_tab);
  3147.             break;
  3148.         case "News":
  3149.             su_select_topic("news", mode, new_tab);
  3150.             break;
  3151.         case "Wiki":
  3152.             su_select_topic("wiki", mode, new_tab);
  3153.             break;
  3154.         default:
  3155.             su_select_topic(mode, mode, new_tab);
  3156.             break;
  3157.     }
  3158. }
  3159.  
  3160. function su_handle_domain_mode_click(event, domain)
  3161. {
  3162.     su_select_topic("TAG_" + domain, domain, su_new_tab(event));
  3163. }
  3164.  
  3165. function su_select_topic(topic, label, new_tab, opt_force_stumble)
  3166. {
  3167.     topic += "";
  3168.     var lang = false;
  3169.     switch (topic)
  3170.     {
  3171.         case "0":
  3172.             su_set_mode(topic, label, "", "Stumble!", "Show next page");
  3173.             break;
  3174.         case "44":
  3175.             su_set_mode(topic, label, 
  3176.                         "chrome://stumbleupon/content/skin/stumblers.png",
  3177.                         "Stumble! ", "Stumble a profile");
  3178.             break;
  3179.         case "302":
  3180.             su_set_mode(topic, label, 
  3181.                         "chrome://stumbleupon/content/skin/icon_tb_photo_hover.png",
  3182.                         "Stumble! ", "Stumble a photo");
  3183.             break;
  3184.         case "friends":
  3185.             su_set_mode(topic, label, 
  3186.                         "chrome://stumbleupon/content/skin/icon_tb_people.png",
  3187.                         "Stumble! ", "Stumble a favorite");
  3188.             break;
  3189.         case "video":
  3190.             su_set_mode(topic, label, 
  3191.                         "chrome://stumbleupon/content/skin/video.png",
  3192.                         "Stumble! ", "Stumble a video");
  3193.             break;
  3194.         case "news":
  3195.             su_set_mode(topic, label,
  3196.                         "chrome://stumbleupon/content/skin/icon_tb_news.png",
  3197.                         "Stumble! ", "Stumble a news item");
  3198.             break;
  3199.         case "wiki":
  3200.             su_set_mode(topic, label,
  3201.                         "chrome://stumbleupon/content/skin/wiki.png",
  3202.                         "Stumble! ", "Stumble an article");
  3203.             break;
  3204.         default:
  3205.             if (su_isInt(topic))
  3206.             {
  3207.                 su_set_mode(topic, label,
  3208.                             "chrome://stumbleupon/content/skin/topic.png", 
  3209.                             "Stumble! ", "Stumble " + su_prefix_article(label) + " page");
  3210.             }
  3211.             else if (topic.indexOf("LANG_") == 0)
  3212.             {
  3213.                 lang = true;
  3214.                 su_set_mode(topic, label,
  3215.                             "chrome://stumbleupon/content/skin/topic.png", 
  3216.                             "Stumble! ", "Stumble " + su_prefix_article(label) + " page");
  3217.             }
  3218.             else if (topic.indexOf("TAG_") == 0)
  3219.             {
  3220.                 var tmp_topic = topic.substr(4).toLowerCase();
  3221.                 var favicon_url = null;
  3222.                 if (su_ds.isThruDomain(tmp_topic))
  3223.                 {
  3224.                     // If they've stumbled in a thru domain, we don't need to
  3225.                     // educate via an info bubble. -- JW
  3226. //                    su_ds.setValue("$shown_thru_domain_info_count", su_ds.getValue("~shown_thru_domain_info_count_max"));
  3227.                     
  3228.                     favicon_url = su_get_favicon_url(tmp_topic);
  3229.                 }
  3230.                 
  3231.                 if (favicon_url)
  3232.                 {
  3233.                     su_set_mode(topic, label, favicon_url,
  3234.                                 "Stumble! ", "Stumble a page from " + label);
  3235.                 }
  3236.                 else
  3237.                 {
  3238.                     su_set_mode(topic, label,
  3239.                                 "chrome://stumbleupon/content/skin/search.png",
  3240.                                 "Stumble! ", "Stumble a '" + label + "' page");
  3241.                 }
  3242.             }
  3243.             else if (su_is_mutual_friend(topic))
  3244.             {
  3245.                 su_set_mode(topic, label,
  3246.                             "chrome://stumbleupon/content/skin/mutual_favorites.png",
  3247.                             "Stumble! ", "Stumble a favorite from " + label);
  3248.             }
  3249.             else
  3250.             {
  3251.                 su_set_mode(topic, label,
  3252.                             "chrome://stumbleupon/content/skin/stumbler_favorites.png",
  3253.                             "Stumble! ", "Stumble a favorite from " + label);
  3254.             }
  3255.             break;
  3256.     }
  3257.     
  3258. //    if (! search)
  3259. //    {
  3260. //        su_get_element("su_searchbox").value = "";
  3261. //        su_get_element("su_searchbox").removeAttribute("mode");
  3262. //        su_old_search = "";
  3263. //        su_last_typed_tag = 0;
  3264. //        su_visited_searchbox = 1;
  3265. //    }
  3266.  
  3267.     if (su_ds.getValue("$stumble_upon_change") || opt_force_stumble)
  3268.         stumble(new_tab);
  3269. }
  3270.  
  3271. function su_backup_places(error_label)
  3272. {
  3273.     // Make a snapshot of bookmarks in the standard backup location, but
  3274.     // don't clobber an existing one.
  3275.     try {
  3276.     
  3277.     var datestr = (new Date).toLocaleFormat("%Y-%m-%d");
  3278.     var name = PlacesUIUtils.getFormattedString("bookmarksBackupFilenameJSON", [datestr]); 
  3279.     var nsifile = su_ds.getResourceNSIFile("temp", name);
  3280.     
  3281.     su_ds.deleteFile(nsifile);
  3282.     
  3283.     nsifile.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0700);
  3284.     
  3285.     PlacesUtils.backupBookmarksToFile(
  3286.             nsifile,
  3287.             [PlacesUIUtils.leftPaneFolderId]);
  3288.     
  3289.     var target_dir = su_get_service( 
  3290.             "@mozilla.org/file/directory_service;1",
  3291.             "nsIProperties")
  3292.             .get("ProfD", Components.interfaces.nsIFile);
  3293.     target_dir.append("bookmarkbackups");
  3294.     if (! target_dir.exists())
  3295.         target_dir.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0700);
  3296.     
  3297.     var target_file;
  3298.     target_file = su_get_service(
  3299.             "@mozilla.org/file/directory_service;1",
  3300.             "nsIProperties")
  3301.             .get("ProfD", Components.interfaces.nsIFile);
  3302.     target_file.append("bookmarkbackups");
  3303.     target_file.append(name);
  3304.     if (target_file.exists())
  3305.     {
  3306.         var target_file2;
  3307.         target_file2 = su_get_service(
  3308.                 "@mozilla.org/file/directory_service;1",
  3309.                 "nsIProperties")
  3310.                 .get("ProfD", Components.interfaces.nsIFile);
  3311.         target_file2.append("bookmarkbackups");
  3312.         target_file2.append(name + ".su.saved.json");
  3313.         if (! target_file2.exists())
  3314.             target_file.copyTo(target_dir, name + ".su.saved.json");
  3315.         su_ds.deleteFile(target_file);
  3316.     }
  3317.     
  3318.     if (! target_file.exists())
  3319.         nsifile.copyTo(target_dir, name);
  3320.     
  3321.     } catch (e) { su_log_error(error_label, e); }
  3322. }
  3323.  
  3324. function su_handle_download_favs_command()
  3325. {
  3326.     var detail = new Object();
  3327.     detail.browser_label = su_host.label;
  3328.     
  3329.     window.openDialog(
  3330.             "chrome://stumbleupon/content/downloadFavsDialog.xul",
  3331.             "su_downloadFavsDialog",
  3332.             "chrome,dialog,centerscreen,dependent",
  3333.             detail);
  3334. }
  3335.  
  3336. function su_download_favs(start_download)
  3337. {
  3338.     if (start_download)
  3339.         su_ds.setValue("$sync_bm_meta", true);
  3340.     
  3341.     var state = su_ds.getValue("$download_favs_state");
  3342.     var context;
  3343.     var val;
  3344.     if (((state == "a") || (state == "c")) && (! start_download))
  3345.         return;
  3346.     
  3347.     context = su_ds.getValue("$download_favs_detail");
  3348.     
  3349.     if ((state == "a") || (state == "c") || (! context.mode))
  3350.     {
  3351.         context = new Object();
  3352.         context.begin_s = su_get_time_s();
  3353.         context.end_s = 0;
  3354.         context.prekey = 0;
  3355.         context.prekey2 = 0;
  3356.         context.mode = 1;
  3357.         context.first = 1;
  3358.         context.download_target_count = 200;
  3359.         context.download_count = 0;
  3360.         context.apply_target_count = 200;
  3361.         context.apply_count = 0;
  3362.         context.count = 0;
  3363.         context.done = false;
  3364.         context.stopped = false;
  3365.         su_ds.setValue("$download_favs_detail", context);
  3366.         su_ds.setValue("#download_favs_detail", context);
  3367.         su_ds.setValue("$download_favs_state", "b");
  3368.         su_ds.flushPrefs();
  3369.     }
  3370.     else
  3371.     {
  3372.         su_ds.setValue("#download_favs_detail", context);
  3373.     }
  3374.     
  3375.     if (su_preference_dialog)
  3376.     {
  3377.         val = 5;
  3378.         
  3379.         el = su_preference_dialog.ownerDocument.getElementById("download_progress");
  3380.         if (val != el.value)
  3381.             el.value = val;
  3382.     }
  3383.  
  3384.     su_set_download_favs_enabled(false);
  3385.     
  3386.     if (su_ds.getValue("#migrating_places"))
  3387.         return;
  3388.     
  3389.     setTimeout(function (win, context) { win.su_download_favs_getmetafavs(context) }, 0, window, context);
  3390. }
  3391.  
  3392. function su_download_favs_getmetafavs(context)
  3393. {
  3394.     var params = "";
  3395.     params = su_arp(params, "prekey", context.prekey);
  3396.     params = su_arp(params, "prekey2", context.prekey2);
  3397.     params = su_arp(params, "first", context.first);
  3398.     params = su_arp(params, "mode", context.mode);
  3399.     params = su_arp(params, "a", (su_ds.getValue("$sync_bm_adult") ? 1 : 0))
  3400.     context.quiet = true;
  3401.     su_post_url_server_async(
  3402.                 "getmetafavs.php",
  3403.                 params,
  3404.                 15000,
  3405.                 su_download_favs_getmetafavs_done,
  3406.                 context);
  3407. }
  3408.  
  3409. function su_download_favs_getmetafavs_done(res)
  3410. {
  3411.     try {
  3412.         if (res.status != 200)
  3413.             return;
  3414.     } catch (e) { return; } 
  3415.     
  3416.     var context = res.detail;
  3417.     
  3418.     context.first = 0;
  3419.     
  3420.     su_ds.setValue("$download_favs_detail", context);
  3421.     su_ds.flushPrefs();
  3422.     
  3423.     var s = "";
  3424.     if (typeof(res.responseText) != "undefined")
  3425.         s = res.responseText;
  3426.     
  3427.     setTimeout(function (win, context, s) {
  3428.                 win.su_download_favs_getmetafavs_done2(context, s); },    
  3429.             0,
  3430.             window,
  3431.             context,
  3432.             s);        
  3433. }
  3434.  
  3435. function su_download_favs_getmetafavs_done2(context, s)
  3436. {
  3437.     if (context.stopped)
  3438.         return;
  3439.     
  3440. //    if (context.paused)
  3441. //    {
  3442. //        setTimeout(function (win, context, s) {
  3443. //                win.su_download_favs_getmetafavs_done2(context, s); },
  3444. //                1000,
  3445. //                window,
  3446. //                context,
  3447. //                s);
  3448. //        return;
  3449. //    }
  3450.     
  3451.     if (su_log_communication)
  3452.         su_log("response getmetafavs.php", s);
  3453.     
  3454.     var commands = s.split("\n");
  3455.     
  3456.     window.setTimeout(function (win, context, commands) {
  3457.             win.su_download_favs2(context, commands); },
  3458.             0,
  3459.             window,
  3460.             context,
  3461.             commands);
  3462. }
  3463.  
  3464. function su_download_favs2(context, commands)
  3465. {
  3466.     var command;
  3467.     var command_parts; 
  3468.     
  3469.     if (su_ds.getValue("$download_favs_state") != "b")
  3470.     {
  3471.         // Download is done or stopped.
  3472.         su_process_command_queue();
  3473.     }
  3474.     else if (commands.length)
  3475.     {
  3476.         command = commands.shift();
  3477.         
  3478.         if (command.indexOf("META ") == 0)
  3479.         {    
  3480.             context.download_count++;
  3481.             su_enqueue_command(16000, command);
  3482.         }
  3483.         else if (command.indexOf("BATCH ") == 0)
  3484.         {
  3485.             command_parts = command.split(" ");
  3486.             context.download_target_count = parseInt(command_parts[3]);
  3487.             context.apply_target_count = parseInt(command_parts[3]);
  3488.             su_ds.setValue("$download_favs_detail", context);
  3489.             su_ds.flushPrefs();
  3490.         }
  3491.         else
  3492.         {
  3493.             su_process_command(command, context);
  3494.         }
  3495.         
  3496.         setTimeout(function (win, context, commands) {
  3497.                     win.su_download_favs2(context, commands); },
  3498.                 10,
  3499.                 window,
  3500.                 context,
  3501.                 commands);
  3502.     }
  3503.     else if (! context.done)
  3504.     {
  3505.         setTimeout(function (win, context) {
  3506.                     win.su_download_favs_getmetafavs(context); },
  3507.                 0,
  3508.                 window,
  3509.                 context);
  3510.         
  3511.         su_process_command_queue();
  3512.     }
  3513.     else if (context.done && (context.mode == 1))
  3514.     {
  3515.         context.mode = 2;
  3516.         context.prekey = 0;
  3517.         context.done = false;
  3518.         
  3519.         setTimeout(function (win, context) {
  3520.                     win.su_download_favs_getmetafavs(context); },
  3521.                 0,
  3522.                 window,
  3523.                 context);
  3524.  
  3525.         su_process_command_queue();
  3526.     }
  3527.     else if (context.done && (context.mode == 2))
  3528.     {
  3529.         context.apply_target_count = context.download_count;
  3530.         context.apply_count = context.download_count - su_count_enqueued_commands(16000);
  3531.         su_ds.setValue("$download_favs_detail", context);
  3532.         su_ds.setValue("$download_favs_state", "c");
  3533.         su_ds.flushPrefs();
  3534.         su_ds.logEvent("dfth");
  3535.         su_ds.setValue("#command_queue_context", null);
  3536.         
  3537.         su_process_command_queue();
  3538.     }
  3539.     else
  3540.     {
  3541.         su_log_error("DOWNLOADFAVS TERMINATION", context, commands.length);
  3542.     }
  3543. }
  3544.  
  3545. function su_add_query_folder_bm(parent_folderid, target_folderids, tag, title, index)
  3546. {
  3547.     var hs = su_ds.getHistoryService();
  3548.     var query = hs.getNewQuery();
  3549.     var bms = su_ds.getBookmarksService();
  3550.     query.setFolders(target_folderids, target_folderids.length);
  3551.     query.searchTerms = tag;
  3552.     var opt = hs.getNewQueryOptions();
  3553.     opt.sortingMode = opt.SORT_BY_LASTMODIFIED_DESCENDING;
  3554.     opt.resultType = opt.RESULTS_AS_URI;
  3555.     opt.queryType = 1;
  3556.     var query_str = hs.queriesToQueryString([query], 1, opt);
  3557.     var ios = su_get_service(
  3558.             "@mozilla.org/network/io-service;1",
  3559.             "nsIIOService");
  3560.     var nsiuri = ios.newURI(query_str, null, null);
  3561.     
  3562.     return bms.insertBookmark(
  3563.             parent_folderid,
  3564.             nsiuri,
  3565.             index,
  3566.             title);
  3567. }
  3568.  
  3569. function su_get_favicon_url(domain)
  3570. {
  3571.     if (! domain)
  3572.         return null;
  3573.     
  3574.     filename = su_get_channel_id(domain) + ".ico";
  3575.     
  3576.     if (! su_ds.isResourceInstalled("favicons", filename))
  3577.         return null;
  3578.     
  3579.     return su_ds.getResourceURLFromName("favicons", filename);
  3580. }
  3581.  
  3582. function su_get_channel_id(domain)
  3583. {
  3584.     return domain.replace(/\./g, "_");
  3585. }
  3586.  
  3587. function su_set_mode_all()
  3588. {
  3589.     su_set_mode("0", "All", "", "Stumble!", "Show next page");
  3590. }
  3591.  
  3592. function su_set_mode(cat, cat_label, src, label, tooltip)
  3593. {
  3594.     cat += "";
  3595.     var el;
  3596.     el = su_get_element("su_cat_langall");
  3597.     if (el)
  3598.         el.hidden = (cat.indexOf("LANG_") != 0);
  3599.     
  3600.     el = su_get_element("su_cat_" + cat);
  3601.     if (el)
  3602.         su_get_element("su_category").selectedItem = el;
  3603.     
  3604.     su_selected_category = cat + "";
  3605.     
  3606.     var tweakedCat = '';
  3607.     if(cat_label)
  3608.     {
  3609.         tweakedCat = cat_label.replace(/\.com$/igm, "");
  3610.         if(tweakedCat.length > 30)
  3611.             tweakedCat = tweakedCat.slice(0, 27) + "...";
  3612.     }
  3613.     su_set_label("su_category", tweakedCat);
  3614.  
  3615.     if (! ((stumbleid == 0) && (! su_promo_mode)))
  3616.     {
  3617.         su_set_label("su_stumble", label);
  3618.         su_get_element("su_stumble").setAttribute("image2", src);
  3619.         su_get_element("su_stumble").setAttribute("tooltiptext", tooltip);
  3620.     }
  3621. }
  3622.  
  3623. function su_refresh_category_selector_batched()
  3624. {
  3625.     // By delaying for 500 ms, we batch sets of closely spaced menu 
  3626.     // updates.
  3627.     if (! su_refreshing_category_selector)
  3628.     {
  3629.         su_refreshing_category_selector = true;
  3630.         su_blocked_category_selector_refresh_pending = false;
  3631.         setTimeout(
  3632.                     function (win) {
  3633.                         win.su_invoke_global_event("refresh-category-selector", null); },
  3634.                     500,
  3635.                     window);
  3636.     }
  3637.     else if (su_refreshing_category_selector && 
  3638.                 (! su_blocked_category_selector_refresh_pending))
  3639.     {
  3640.         // If refresh is blocked, push back the refresh event.
  3641.         su_blocked_category_selector_refresh_pending = true;
  3642.         setTimeout(
  3643.                     function (win) {
  3644.                         win.su_refresh_category_selector_batched(); },
  3645.                     500,
  3646.                     window);
  3647.     }
  3648. }
  3649.  
  3650. // This is the javascript way of creating an object and it's constructor:
  3651. function su_CatObj(id, name)
  3652. {
  3653.     this.id = id;
  3654.   this.name = name;
  3655. }
  3656.  
  3657. // Updates interest list in the in-cat stumble dialog, and saves current interests to disk (su_user_interests)
  3658. function su_refresh_category_selector()
  3659. {
  3660.     // we need to completely *remove* the menupopup and readd it
  3661.     // if we don't, the menupopup will be corrupt and it willl eventually 
  3662.     // stop working.  this is a firefox specific problem    
  3663.     var incat = su_get_element("su_category");
  3664.  
  3665.     // delete the menupopup and regenerate it
  3666.     var thechild;
  3667.     thechild = incat.childNodes[0];
  3668.     if (typeof(thechild.hidePopup) == "function")
  3669.     {
  3670.         thechild.hidePopup();
  3671.         su_unfocus();
  3672.     }
  3673.     incat.removeChild(thechild);
  3674.     
  3675.     var ja = document.createElement("menupopup");
  3676.     incat.appendChild(ja);
  3677.  
  3678.     su_load_categories();
  3679.  
  3680.     // Now add new children
  3681.     var ints = new Array();
  3682.     if (su_user_interests.length)
  3683.     {
  3684.         var cat2;
  3685.         for (cat2 in su_user_interests)
  3686.         {
  3687.             if (su_is_property_garbage(su_user_interests, cat2))
  3688.                 continue;
  3689.             
  3690.             if (su_is_property_garbage(su_catnames, cat2))
  3691.                 continue;
  3692.     
  3693.             if ((typeof(su_catnames[cat2])) == "undefined")
  3694.                 continue;
  3695.  
  3696.             ints.push(new su_CatObj(cat2, su_catnames[cat2]));
  3697.         }
  3698.     }
  3699.     
  3700.     ints.sort(function (a, b) 
  3701.                 {
  3702.                     if ( a.name < b.name ) return -1;
  3703.                     if ( a.name > b.name ) return 1;
  3704.                     return 0;
  3705.                 });
  3706.  
  3707.     // ** An individual stumbler
  3708.     ja = document.createElement("menuitem");
  3709.     ja.setAttribute("class", "menuitem-iconic");
  3710.     ja.setAttribute("label", "Pages from...");
  3711.     ja.setAttribute("id", "su_cat_favorites_of2");
  3712.     ja.setAttribute("tooltiptext", "Stumble someone's favorites");
  3713.     ja.setAttribute("onclick", "su_favorites_of(event);");
  3714.     ja.setAttribute("image", "chrome://stumbleupon/content/skin/stumbler_favorites.png");
  3715.     ja.setAttribute("hidden", "true");
  3716.     incat.childNodes[0].appendChild(ja);
  3717.  
  3718.     // ** stumble in "all"
  3719.  
  3720.     ja = document.createElement("menuitem");
  3721.     ja.setAttribute("class", "menuitem-iconic");
  3722. //    ja.setAttribute("label", su_ds.getValue("%menu.anytopic"));
  3723.     ja.setAttribute("label", "All");
  3724.     ja.setAttribute("id", "su_cat_0");
  3725.     ja.setAttribute("tooltiptext", "Stumble all");
  3726.     ja.setAttribute("oncommand", "su_select_topic(0, 'All', false);");
  3727.     ja.setAttribute("image", "chrome://stumbleupon/content/skin/all.png");
  3728.     incat.childNodes[0].appendChild(ja);
  3729.  
  3730.     // ** Subscriptions
  3731.     
  3732.     ja = document.createElement("menuitem");
  3733.     ja.setAttribute("class", "menuitem-iconic");
  3734. //    ja.setAttribute("label", su_ds.getValue("%menu.anytopic"));
  3735.     ja.setAttribute("label", "Subscriptions");
  3736.     ja.setAttribute("id", "su_cat_friends");
  3737.     ja.setAttribute("tooltiptext", "Sites from people I've subscribed to");
  3738.     ja.setAttribute("oncommand", "su_select_topic('friends', 'Subscriptions', false);");
  3739.     ja.setAttribute("image", "chrome://stumbleupon/content/skin/icon_tb_people.png");
  3740.     incat.childNodes[0].appendChild(ja);
  3741.  
  3742.     // ** StumbeThru
  3743.     
  3744.     ja = document.createElement("menuitem");
  3745.     ja.setAttribute("class", "menuitem-iconic");
  3746.     ja.setAttribute("label", "StumbleThru");
  3747.     ja.setAttribute("id", "su_cat_stumblethru");
  3748.     ja.setAttribute("tooltiptext", "StumbleThru a website");
  3749.     ja.setAttribute("oncommand", 'su_set_server_location("stumblethru.php");');
  3750.     ja.setAttribute("image", "chrome://stumbleupon/content/skin/domain.png");
  3751.     incat.childNodes[0].appendChild(ja);
  3752.  
  3753.     // ** Search
  3754.     
  3755.     ja = document.createElement("menuitem");
  3756.     ja.setAttribute("class", "menuitem-iconic");
  3757.     ja.setAttribute("label", "Search");
  3758.     ja.setAttribute("id", "su_cat_stumble_tags");
  3759.     ja.setAttribute("tooltiptext", "Stumble within a query");
  3760.     ja.setAttribute("oncommand", 'su_handle_mode_click(event, "Search");');
  3761.     ja.setAttribute("image", "chrome://stumbleupon/content/skin/search.png");
  3762.     incat.childNodes[0].appendChild(ja);
  3763.  
  3764.     // ** Photos
  3765.     
  3766.     ja = document.createElement("menuitem");
  3767.     ja.setAttribute("class", "menuitem-iconic");
  3768. //    ja.setAttribute("label", su_ds.getValue("%menu.anytopic"));
  3769.     ja.setAttribute("label", "Photos");
  3770.     ja.setAttribute("id", "su_cat_photos");
  3771.     ja.setAttribute("tooltiptext", "Stumble an image");
  3772.     ja.setAttribute("oncommand", "su_select_topic(302, 'Photos', false);");
  3773.     ja.setAttribute("image", "chrome://stumbleupon/content/skin/icon_tb_photo_hover.png");
  3774.     incat.childNodes[0].appendChild(ja);
  3775.  
  3776.     // ** Videos
  3777.     
  3778.     ja = document.createElement("menuitem");
  3779.     ja.setAttribute("class", "menuitem-iconic");
  3780. //    ja.setAttribute("label", su_ds.getValue("@menu.anytopic"));
  3781.     ja.setAttribute("label", "Videos");
  3782.     ja.setAttribute("id", "su_cat_video");
  3783.     ja.setAttribute("tooltiptext", "Stumble a video");
  3784.     ja.setAttribute("oncommand", "su_select_topic('video', 'Videos', false);");
  3785.     ja.setAttribute("image", "chrome://stumbleupon/content/skin/video.png");
  3786.     incat.childNodes[0].appendChild(ja);
  3787.  
  3788.     // ** News
  3789.  
  3790.     ja = document.createElement("menuitem");
  3791.     ja.setAttribute("class", "menuitem-iconic");
  3792. //    ja.setAttribute("label", su_ds.getValue("%menu.anytopic"));
  3793.     ja.setAttribute("label", "News");
  3794.     ja.setAttribute("id", "su_cat_news");
  3795.     ja.setAttribute("tooltiptext", "Stumble news");
  3796.     ja.setAttribute("oncommand", "su_select_topic('news', 'News', false);");
  3797.     ja.setAttribute("image", "chrome://stumbleupon/content/skin/icon_tb_news.png");
  3798.     incat.childNodes[0].appendChild(ja);
  3799.     
  3800.     // ** contextual...
  3801.     
  3802.     // Create favorites of menu
  3803.     var random_topic_id = 499;
  3804.     var random_topic_name = 'StumbleUpon';
  3805.         
  3806.     ja = document.createElement("menuitem");
  3807.     ja.setAttribute("class", "menuitem-iconic");    
  3808.     ja.setAttribute("label", "More from " + random_topic_name);
  3809.     ja.setAttribute("tooltiptext", "More from " + random_topic_name);
  3810.     ja.setAttribute("id", "su_cat_morefrom");
  3811.     ja.setAttribute("hidden", "true");
  3812.     ja.setAttribute("oncommand", "su_select_topic(" + random_topic_id + ", '" + random_topic_name + "', false);");
  3813.     ja.setAttribute("image", "chrome://stumbleupon/content/skin/topic.png");
  3814.     incat.childNodes[0].appendChild(ja);
  3815.  
  3816.     var preTopicsItem = ja;
  3817.  
  3818.     var i;
  3819.     if (ints.length < 21)
  3820.     {
  3821.         for (i = 0; i < ints.length; i++)
  3822.         {
  3823.             var newname
  3824.             try {
  3825.                 newname = ints[i].name.replace(/'/g, "\\\'");
  3826.             }
  3827.             catch (e) {
  3828.                 su_log_error("CAT NEWNAME", ints[i], i);
  3829.                 continue;
  3830.             }
  3831.             ja = document.createElement("menuitem");
  3832.             ja.setAttribute("label", ints[i].name);
  3833.             ja.setAttribute("id", "su_cat_" + ints[i].id);
  3834.             ja.setAttribute("tooltiptext", "Stumble " + ints[i].name);
  3835.             ja.setAttribute("oncommand", "su_select_topic(" + ints[i].id + ",'" + newname + "', false);");
  3836.             incat.childNodes[0].appendChild(ja);
  3837.         }
  3838.     }
  3839.     else
  3840.     {
  3841.         var folders = new Array();
  3842.         for (var cat in su_user_interests)
  3843.         {
  3844.             if (su_is_property_garbage(su_user_interests, cat))
  3845.                 continue;
  3846.             
  3847.             if (su_is_property_garbage(su_topicfolders, cat))
  3848.                 continue;
  3849.             
  3850.             if (su_is_property_garbage(su_catnames, cat))
  3851.                 continue;
  3852.             
  3853.             var folder = su_topicfolders[cat];
  3854.             var name = su_catnames[cat];
  3855.             if (typeof(folders[folder]) == "undefined")
  3856.                 folders[folder] = new Array();
  3857.         
  3858.             folders[folder][name]=cat;
  3859.         }
  3860.     
  3861.         for (i = 0; i < su_foldernames.length; i++)
  3862.         {
  3863.             var key = su_foldernames[i];
  3864.             if (typeof(folders[key]) == "undefined")
  3865.                     continue;
  3866.             // topics = folders[key];
  3867.  
  3868.             ja = document.createElement("menu");
  3869.             ja.setAttribute("label", key);
  3870.             ja.setAttribute("tooltiptext", "Stumble...");
  3871.             var child = incat.childNodes[0].appendChild(ja);
  3872.     
  3873.             ja = document.createElement("menupopup");
  3874.             var child2 = child.appendChild(ja);
  3875.  
  3876.             var newtopics = new Array();
  3877.             var counter = 0;
  3878.             for (var catname in folders[key])
  3879.             {
  3880.                 if (su_is_property_garbage(folders[key], catname))
  3881.                     continue;
  3882.                 
  3883.                 newtopics[counter] = catname;
  3884.                 counter++;    
  3885.  
  3886.             }
  3887.             newtopics.sort();
  3888.             for (var j = 0; j < newtopics.length; j++)
  3889.             {
  3890.                 name = newtopics[j];
  3891.                 var catid = su_catids[name];
  3892.  
  3893.                 ja = document.createElement("menuitem");
  3894.                 ja.setAttribute("class", "topic-selector");
  3895.                 ja.setAttribute("label", name);
  3896.                 ja.setAttribute("id", "su_cat_" + catid);
  3897.                 ja.setAttribute("tooltiptext", "Stumble " + name);
  3898.                 newname = name.replace(/'/g, "\\\'");
  3899.                 ja.setAttribute("oncommand", "su_select_topic(" + catid + ",'" + newname + "', false);");
  3900.                 child2.appendChild(ja);
  3901.             }
  3902.         }
  3903.     }
  3904.  
  3905.     if(preTopicsItem !== incat.childNodes[0].lastChild)
  3906.     {
  3907.         // If we have favorite topics, then include a separator before them
  3908.         ja = document.createElement("menuseparator");
  3909.         incat.childNodes[0].insertBefore(ja, preTopicsItem.nextSibling);
  3910.     }
  3911.  
  3912.     ja = document.createElement("menuseparator");
  3913.     incat.childNodes[0].appendChild(ja);
  3914.  
  3915.     ja = document.createElement("menuitem");
  3916. //    ja.setAttribute("class", "topic-selector");
  3917. //    ja.setAttribute("label", su_ds.getValue("%menu.addmoretopics"));
  3918.     ja.setAttribute("label", "Update Topics");
  3919.     ja.setAttribute("tooltiptext", "Select different topics");
  3920.     ja.setAttribute("id", "su_cat_addmore");
  3921.     ja.setAttribute("oncommand", "su_interests_pre();");
  3922.     incat.childNodes[0].appendChild(ja);
  3923.  
  3924.  
  3925.     // Create languages
  3926.     ja = document.createElement("menu");
  3927. //    ja.setAttribute("class", "topic-selector");
  3928.     ja.setAttribute("label", "Languages");
  3929.     ja.setAttribute("tooltiptext", "Stumble pages in a specific language");
  3930.     ja.setAttribute("id", "su_languages");
  3931.     var langs2 = incat.childNodes[0].appendChild(ja);
  3932.  
  3933.     ja = document.createElement("menupopup");
  3934. //    ja.setAttribute("class", "topic-selector");
  3935.     ja.setAttribute("id", "su_languages-popup");
  3936.     langs2.appendChild(ja);
  3937.  
  3938.     // first check to see if favorites of is already there
  3939.     var langs = su_get_element("su_languages-popup");
  3940.  
  3941.     ja = document.createElement("menuitem");
  3942.     ja.setAttribute("label", "All");
  3943. //        ja.setAttribute("class", "topic-selector");
  3944.     ja.setAttribute("id", "su_cat_langall");
  3945.     ja.setAttribute("tooltiptext", "Stumble all");
  3946.     ja.setAttribute("oncommand", "su_select_topic(0, 'All', false);");
  3947.     langs.appendChild(ja);
  3948.  
  3949.     var languages = new Array();
  3950.  
  3951.     languages['ZH'] = "Chinese";
  3952.     languages['DA'] = "Danish";
  3953.     languages['NL'] = "Dutch";
  3954.     languages['FI'] = "Finnish";
  3955.     languages['FR'] = "French";
  3956.     languages['DE'] = "German";
  3957.     languages['EL'] = "Greek";
  3958.     languages['IT'] = "Italian";
  3959.     languages['JA'] = "Japanese";
  3960.     languages['PT'] = "Portuguese";
  3961.     languages['ES'] = "Spanish";
  3962.     languages['SV'] = "Swedish";
  3963.     languages['TR'] = "Turkish";
  3964.  
  3965.     for (var langid in languages)
  3966.     {
  3967.         if (su_is_property_garbage(languages, langid))
  3968.             continue;
  3969.         
  3970.         var langname = languages[langid];
  3971.  
  3972.         ja = document.createElement("menuitem");
  3973.         ja.setAttribute("label", langname);
  3974. //        ja.setAttribute("class", "topic-selector");
  3975.         ja.setAttribute("id", 'su_cat_LANG_' + langid);
  3976.         ja.setAttribute("tooltiptext", "Stumble " + langname + " pages");
  3977.         ja.setAttribute("oncommand", "su_select_topic('" + 'LANG_' + langid + "', '" + langname + "', false);");
  3978.         langs.appendChild(ja);
  3979.     }
  3980.  
  3981.     su_set_mode_all();
  3982.  
  3983.     su_refreshing_category_selector = false;
  3984. }
  3985.  
  3986. function su_favorites_of(event)
  3987. {
  3988.     su_unfocus_searchbox(); 
  3989.     var stumbler = getBrowser().contentWindow.prompt("Enter the nickname of a stumbler:","");
  3990.  
  3991.     // they clicked cancel
  3992.     if (stumbler && (stumbler != ""))
  3993.     {
  3994.         // select and do it
  3995.         su_select_topic(stumbler, stumbler, su_new_tab(event));
  3996.     }
  3997.     else
  3998.     {
  3999.         su_set_mode_all();
  4000.     }
  4001.     return true;
  4002. }
  4003.  
  4004. function su_unfocus_searchbox()
  4005. {      
  4006.     // unfocus search box so we don't end up searching when they hit enter        
  4007.     if (su_get_element("su_searchbox").getAttribute("focused") == "true")
  4008.         su_unfocus();
  4009. }
  4010.  
  4011. function su_unfocus()
  4012. {
  4013.     if (! su_gui_initialized) return;
  4014.     
  4015.     if (document.commandDispatcher.focusedElement)
  4016.     {
  4017.         if ((document.commandDispatcher.focusedElement instanceof NSHTMLElement) || 
  4018.                     (document.commandDispatcher.focusedElement instanceof XULElement))
  4019.         {
  4020.             document.commandDispatcher.focusedElement.blur();
  4021.         }
  4022.         else
  4023.         {
  4024.             // non-HTML/XUL elements have no blur method; see bug 323805
  4025.             document.commandDispatcher.focusedElement = null;
  4026.         }
  4027.     }
  4028. }
  4029.  
  4030. /*
  4031. function su_tag_stumble()
  4032. {
  4033.     su_unfocus_searchbox(); 
  4034.     var tag = getBrowser().contentWindow.prompt("Please enter a tag","");
  4035.  
  4036.     // they clicked cancel
  4037.     if (typeof(tag) == "undefined" || tag == "" || tag.length <= 0)
  4038.     {
  4039.         su_set_mode_all();
  4040.         return false;
  4041.     }
  4042.  
  4043.     // put it in the box
  4044.     su_get_element("su_searchbox").value=tag;
  4045.     su_get_element("su_searchbox").removeAttribute("mode");
  4046.     su_old_search = tag;
  4047.     su_last_typed_tag = 0;
  4048.     su_visited_searchbox = 1;
  4049.  
  4050.     // select and do it
  4051.     su_select_topic('TAG_' + tag, tag, false);
  4052.     return true;
  4053. }
  4054. */
  4055.  
  4056. function su_handle_referral_throbber_click(event)
  4057. {
  4058.     su_stop_referred_throbber();
  4059.     su_set_attribute("su_referred", "disabled", "true");
  4060.     setTimeout(su_handle_referral_throbber_enable, su_ds.getValue("@click_throttle_ms"));
  4061.     su_select_topic(0, "All", su_new_tab(event), true);
  4062. }
  4063.  
  4064. function su_handle_referral_throbber_enable()
  4065. {
  4066.     su_set_attribute("su_referred", "disabled", "false");
  4067.     setTimeout(su_update_referred, 0);
  4068. }
  4069.  
  4070. /*
  4071. function su_handle_report_dupe_command(url)
  4072. {
  4073.     if (su_enable_freereporting)
  4074.     {
  4075.         var media = su_ds.serialize(su_get_media_specs());
  4076.     
  4077.         var params = "";
  4078.         params = su_arp(params, "url", stumbled_url);
  4079.         params = su_arp(params, "redirect", su_redirect_url);
  4080.         params = su_arp(params, "current", su_get_browser_url());
  4081.         params = su_arp(params, "current_media", media);
  4082.     
  4083.         su_post_url_server_async(
  4084.                     "dupe.php",
  4085.                     params,
  4086.                     15000,
  4087.                     su_generic_done);
  4088.     
  4089.         var ps = su_get_service(
  4090.                     "@mozilla.org/embedcomp/prompt-service;1",
  4091.                     "nsIPromptService");
  4092.         
  4093.         ps.alert(window, "StumbleUpon", "Thanks for reporting this duplicate.\n\nIt will be reviewed by our support team.");
  4094.     }
  4095.     else
  4096.     {
  4097.         if (stumbled_url == "")
  4098.         {
  4099.             alert("You can't report pages that you haven't Stumbled upon."); 
  4100.         }
  4101.     
  4102.         if (stumbleid == 0)
  4103.             return;
  4104.     
  4105.         var params = "";
  4106.         params = su_arp(params, "url", stumbled_url);
  4107.         params = su_arp(params, "redirect", su_redirect_url);
  4108.         params = su_arp(params, "current", su_get_browser_url());
  4109.         params = su_arp(params, "verified", 1);
  4110.  
  4111.         if (window.confirm("Are you sure that the following URL contains duplicate content?\n\n" + stumbled_url))
  4112.         {
  4113.             su_post_url_server_async(
  4114.                         "dupe.php",
  4115.                         params,
  4116.                         15000,
  4117.                         su_generic_done);
  4118.         }
  4119.     }
  4120. }
  4121. */
  4122.  
  4123.  
  4124. // Handler for menuitem "Report Miscat"
  4125. function su_handle_report_miscat_command(tab_url)
  4126. {
  4127.     if (su_enable_freereporting)
  4128.     {
  4129.         var url_detail = su_ds.lookup("url:url_detail", tab_url);
  4130.         
  4131.         var loc = "misclassified.php";
  4132.         if (url_detail)
  4133.         {
  4134.             loc = su_arp(loc, "url", url_detail.url, true);
  4135.             loc = su_arp(loc, "redirect", url_detail.redirect_url, true);
  4136.         }
  4137.         else
  4138.         {
  4139.             loc = su_arp(loc, "url", tab_url, true);
  4140.             loc = su_arp(loc, "redirect", tab_url, true);
  4141.         }
  4142.         loc = su_arp(loc, "current", su_get_browser_url(), true);
  4143.         
  4144.         su_set_server_location(loc, null, true);
  4145.     }
  4146.     else
  4147.     {
  4148.         if (stumbled_url == "")
  4149.         {
  4150.             alert("You can't report pages that you haven't Stumbled upon."); 
  4151.             return;
  4152.         }
  4153.     
  4154.         if (stumbleid == 0)
  4155.             return;
  4156.     
  4157.         var loc = "misclassified.php";
  4158.         loc = su_arp(loc, "url", stumbled_url, true);
  4159.         loc = su_arp(loc, "redirect", su_redirect_url, true);
  4160.         loc = su_arp(loc, "current", su_get_browser_url(), true);
  4161.         loc = su_arp(loc, "verified", 1, true);
  4162.         if (window.confirm("Are you sure that the following URL is in the wrong topic?\n\n" + stumbled_url))
  4163.             su_set_server_location(loc, null, true);
  4164.     }
  4165. }
  4166.  
  4167.  
  4168. // Handler for menuitem "Report Adult"
  4169. function su_handle_report_adult_profile_command(tab_url)
  4170. {
  4171.     if (su_enable_freereporting)
  4172.     {
  4173.         var nickname = su_get_profile_nickname(tab_url);
  4174.         
  4175.         var loc = "adult.php";
  4176.         loc = su_arp(loc, "stumbler", nickname);
  4177.         
  4178.         su_set_server_location(loc, null, true);
  4179.     }
  4180.     else
  4181.     {
  4182.         if (stumbled_url == "")
  4183.         {
  4184.             alert("You can't report pages that you haven't Stumbled upon."); 
  4185.             return;
  4186.         }
  4187.     
  4188.         if (stumbleid == 0)
  4189.             return;
  4190.     
  4191.         var url = su_get_browser_url();
  4192.         var nickname = su_get_profile_nickname(url);
  4193.         
  4194.         var loc;
  4195.         if (nickname)
  4196.         {
  4197.             loc = "adult.php";
  4198.             loc = su_arp(loc, "stumbler", nickname, true);
  4199.             loc = su_arp(loc, "verified", 1, true);
  4200.         }
  4201.         else
  4202.         {
  4203.             loc = "misclassified.php";
  4204.             loc = su_arp(loc, "adult_content", 1, true); 
  4205.             loc = su_arp(loc, "url", stumbled_url, true);
  4206.             loc = su_arp(loc, "redirect", su_redirect_url, true);
  4207.             loc = su_arp(loc, "current", url, true);
  4208.             loc = su_arp(loc, "verified", 1, true);
  4209.         }
  4210.  
  4211.         if (window.confirm("Are you sure that the following URL contains adult content?\n\n" + stumbled_url))
  4212.             su_set_server_location(loc, null, true);
  4213.     }
  4214. }
  4215.  
  4216.  
  4217. function su_handle_report_wrong_language_command(tab_url)
  4218. {
  4219.     if (su_enable_freereporting)
  4220.     {
  4221.         var url_detail = su_ds.lookup("url:url_detail", tab_url);
  4222.         
  4223.         var loc = "wrong_language.php";
  4224.         if (url_detail)
  4225.         {
  4226.             loc = su_arp(loc, "url", url_detail.url, true);
  4227.             loc = su_arp(loc, "redirect", url_detail.redirect_url, true);
  4228.         }
  4229.         else
  4230.         {
  4231.             loc = su_arp(loc, "url", tab_url, true);
  4232.             loc = su_arp(loc, "redirect", tab_url, true);
  4233.         }
  4234.         
  4235.         loc = su_arp(loc, "current", su_get_browser_url(), true);
  4236.         
  4237.         su_set_server_location(loc, null, true);
  4238.     }
  4239.     else
  4240.     {
  4241.         if (stumbled_url == "")
  4242.         {
  4243.             alert("You can't report pages that you haven't Stumbled upon."); 
  4244.             return;
  4245.         }
  4246.     
  4247.         if (stumbleid == 0)
  4248.             return;
  4249.     
  4250.         var loc = "wrong_language.php";
  4251.         loc = su_arp(loc, "url", stumbled_url, true);
  4252.         loc = su_arp(loc, "redirect", su_redirect_url, true);
  4253.         loc = su_arp(loc, "current", su_get_browser_url(), true);
  4254.         loc = su_arp(loc, "verified", 1, true);
  4255.         
  4256.         if (window.confirm("Are you sure that the following URL is in the wrong language?\n\n" + stumbled_url))
  4257.             su_set_server_location(loc, null, true);
  4258.     }
  4259. }
  4260.  
  4261. // Handler for menuitem "Report Spam"
  4262. function su_handle_report_spam_command(tab_url)
  4263. {
  4264.     if (su_enable_freereporting)
  4265.     {
  4266.         var url_detail = su_ds.lookup("url:url_detail", tab_url);
  4267.         
  4268.         var loc = "spam.php";
  4269.         if (url_detail)
  4270.         {
  4271.             loc = su_arp(loc, "url", url_detail.url, true);
  4272.             loc = su_arp(loc, "redirect", url_detail.redirect_url, true);
  4273.         }
  4274.         else
  4275.         {
  4276.             loc = su_arp(loc, "url", tab_url, true);
  4277.             loc = su_arp(loc, "redirect", tab_url, true);
  4278.         }
  4279.         loc = su_arp(loc, "current", su_get_browser_url(), true);
  4280.         
  4281.         su_set_server_location(loc, null, true);
  4282.  
  4283. //        ps.alert(window, "StumbleUpon", "Thanks for helping improve stumble selection.");
  4284.     }
  4285.     else
  4286.     {
  4287.         if (stumbled_url == "")
  4288.         {
  4289.             alert("You can't report pages that you haven't Stumbled upon."); 
  4290.             return;
  4291.         }
  4292.     
  4293.         if (stumbleid == 0)
  4294.             return;
  4295.     
  4296.         var loc = "spam.php";
  4297.         loc = su_arp(loc, "url", stumbled_url, true);
  4298.         loc = su_arp(loc, "redirect", su_redirect_url, true);
  4299.         loc = su_arp(loc, "current", su_get_browser_url(), true);
  4300.         loc = su_arp(loc, "verified", 1, true);
  4301.         
  4302.         if (window.confirm("Are you sure that the following URL is spam?\n\n" + stumbled_url))
  4303.             su_set_server_location(loc, null, true);
  4304.     }
  4305. }
  4306.  
  4307. function su_handle_report_badware_command(tab_url)
  4308. {
  4309.     if (su_enable_freereporting)
  4310.     {
  4311.         var url_detail = su_ds.lookup("url:url_detail", tab_url);
  4312.         
  4313.         var params = "";
  4314.         if (url_detail)
  4315.         {
  4316.             loc = su_arp(loc, "url", url_detail.url, true);
  4317.             loc = su_arp(loc, "redirect", url_detail.redirect_url, true);
  4318.         }
  4319.         else
  4320.         {
  4321.             loc = su_arp(loc, "url", tab_url, true);
  4322.             loc = su_arp(loc, "redirect", tab_url, true);
  4323.         }
  4324.         params = su_arp(params, "current", su_get_browser_url());
  4325.         
  4326.         su_post_url_server_async(
  4327.                 "badware.php",
  4328.                 params,
  4329.                 15000,
  4330.                 function (){});
  4331.  
  4332.         var ps = su_get_service(
  4333.                     "@mozilla.org/embedcomp/prompt-service;1",
  4334.                     "nsIPromptService");
  4335.         
  4336.         ps.alert(window, "StumbleUpon", "Thanks for reporting this stumble.\n\nIt will be reviewed by our support team.");
  4337.     }
  4338.     else
  4339.     {
  4340.         if (stumbled_url == "")
  4341.         {
  4342.             alert("You can't report pages that you haven't Stumbled upon."); 
  4343.         }
  4344.     
  4345.         if (stumbleid == 0)
  4346.             return;
  4347.     
  4348.         var params = "";
  4349.         params = su_arp(params, "url", stumbled_url);
  4350.         params = su_arp(params, "redirect", su_redirect_url);
  4351.         params = su_arp(params, "current", su_get_browser_url());
  4352.         params = su_arp(params, "verified", 1);
  4353.  
  4354.         if (window.confirm("Are you sure that the following URL contains hostile content?\n\n" + stumbled_url))
  4355.         {
  4356.             su_post_url_server_async(
  4357.                     "badware.php",
  4358.                     params,
  4359.                     15000,
  4360.                     su_generic_done);
  4361.         }
  4362.     }
  4363. }
  4364.  
  4365. // Handler for menuitem "Report 404"
  4366. function su_handle_report_404_command(tab_url)
  4367. {
  4368.     //!!! we shouldn't really report 404, it should be something else (user 404?)
  4369.     if (su_enable_freereporting)
  4370.     {
  4371.         var url_detail = su_ds.lookup("url:url_detail", tab_url);
  4372.         
  4373.         var params = "";
  4374.         if (url_detail)
  4375.         {
  4376.             params = su_arp(params, "url", url_detail.url);
  4377.             params = su_arp(params, "redirect", url_detail.redirect_url);
  4378.         }
  4379.         else
  4380.         {
  4381.             params = su_arp(params, "url", tab_url);
  4382.             params = su_arp(params, "redirect", tab_url);
  4383.         }
  4384.         params = su_arp(params, "current", su_get_browser_url());
  4385.         params = su_arp(params, "status", 404);
  4386.     
  4387.         su_post_url_server_async(
  4388.                 "404.php",
  4389.                 params,
  4390.                 15000,
  4391.                 su_generic_done);
  4392.         
  4393.         var ps = su_get_service(
  4394.                     "@mozilla.org/embedcomp/prompt-service;1",
  4395.                     "nsIPromptService");
  4396.         
  4397.         ps.alert(window, "StumbleUpon", "Thanks for reporting this broken page.\n\nIt will be reviewed by our support team.");
  4398.     }
  4399.     else
  4400.     {
  4401.         if (stumbled_url == "")
  4402.         {
  4403.             alert("You can't report pages that you haven't Stumbled upon."); 
  4404.         }
  4405.     
  4406.         if (stumbleid == 0)
  4407.             return;
  4408.     
  4409.         var params = "";
  4410.         params = su_arp(params, "url", stumbled_url);
  4411.         params = su_arp(params, "redirect", su_redirect_url);
  4412.         params = su_arp(params, "current", su_get_browser_url());
  4413.         params = su_arp(params, "status", 404);
  4414.         params = su_arp(params, "verified", 1);
  4415.  
  4416.         if (window.confirm("Are you sure that the following URL is 404 or broken?\n\n" + stumbled_url))
  4417.         {
  4418.             su_post_url_server_async(
  4419.                     "404.php",
  4420.                     params,
  4421.                     15000,
  4422.                     su_generic_done);
  4423.             //alert("404 reported for page:\n\n" + stumbled_url);
  4424.         }
  4425.     }
  4426. }
  4427.  
  4428. function su_handle_report_inaccurate_command(tab_url)
  4429. {
  4430.     if (su_enable_freereporting)
  4431.     {
  4432.         var url_detail = su_ds.lookup("url:url_detail", tab_url);
  4433.         
  4434.         var params = "";
  4435.         if (url_detail)
  4436.         {
  4437.             params = su_arp(params, "url", url_detail.url);
  4438.             params = su_arp(params, "redirect", url_detail.redirect_url);
  4439.         }
  4440.         else
  4441.         {
  4442.             params = su_arp(params, "url", tab_url);
  4443.             params = su_arp(params, "redirect", tab_url);
  4444.         }
  4445.         params = su_arp(params, "current", su_get_browser_url());
  4446.         
  4447.         su_post_url_server_async(
  4448.                     "inaccurate.php",
  4449.                     params,
  4450.                     15000,
  4451.                     su_generic_done);
  4452.         
  4453.         var ps = su_get_service(
  4454.                     "@mozilla.org/embedcomp/prompt-service;1",
  4455.                     "nsIPromptService");
  4456.         
  4457.         ps.alert(window, "StumbleUpon", "Thanks for helping improve stumble selection.");
  4458.     }
  4459.     else
  4460.     {
  4461.         if (stumbled_url == "")
  4462.         {
  4463.             alert("You can't report pages that you haven't Stumbled upon."); 
  4464.         }
  4465.     
  4466.         if (stumbleid == 0)
  4467.             return;
  4468.     
  4469.         var params = "";
  4470.         params = su_arp(params, "url", stumbled_url);
  4471.         params = su_arp(params, "redirect", su_redirect_url);
  4472.         params = su_arp(params, "current", su_get_browser_url());
  4473.         params = su_arp(params, "verified", 1);
  4474.  
  4475.         if (window.confirm("Are you sure that the following URL contains inaccurate information?\n\n" + stumbled_url))
  4476.         {
  4477.             su_post_url_server_async(
  4478.                         "inaccurate.php",
  4479.                         params,
  4480.                         15000,
  4481.                         su_generic_done);
  4482.         }
  4483.     }
  4484. }
  4485.  
  4486. function su_handle_filter_command(tmp_adult)
  4487. {
  4488.     var params = "";
  4489.     params = su_arp(params, "sadult", tmp_adult);
  4490.     su_post_url_server_async(
  4491.             "setoption.php",
  4492.             params,
  4493.             15000,
  4494.             su_generic_done);
  4495. }
  4496.  
  4497. // Handler for menuitem "Change Current User" and used by newuserWindow
  4498. function su_show_signin_dialog()
  4499. {
  4500.     su_unfocus_searchbox(); 
  4501.     
  4502.     var detail = new Object();
  4503.     
  4504.     detail.userid = "";
  4505.     detail.password = "";
  4506.     detail.nickname = "";
  4507.     detail.enableg = 0;
  4508.     detail.enableu = 0;
  4509.     detail.disableu = 0;
  4510.     detail.disableg = 0;
  4511.     detail.autologout = false;
  4512.     
  4513.     window.openDialog(
  4514.                 "chrome://stumbleupon/content/signinDialog.xul", 
  4515.                 "su_sign_in",
  4516.                 "chrome,modal,dialog,centerscreen,dependent",
  4517.                 detail);
  4518. }
  4519.  
  4520. function su_get_autologout_for_user(str)
  4521. {
  4522.     var pref = "stumble." + str + ".autologout";
  4523.     if (su_ds.isPrefDefined(pref))
  4524.     {
  4525.         // easy, uncommon case where str is the userid
  4526.         return su_ds.getValue(pref);
  4527.     }
  4528.     
  4529.     // more common case where str is the nickname
  4530.     var ids = su_ds.getValue("@id_list").split(":");
  4531.     
  4532.     var i;
  4533.     for (i = 0; i < ids.length; i++)
  4534.     {
  4535.         if (ids[i] == "") continue;
  4536.         if (su_ds.isPrefDefined("stumble." + ids[i] + ".nick") &&
  4537.                     (str == su_ds.getValue("stumble." + ids[i] + ".nick")))
  4538.         {
  4539.             return su_ds.getPrefValue("stumble." + ids[i] + ".autologout", false);
  4540.         }
  4541.     }
  4542.     return false;
  4543. }
  4544.  
  4545. function su_handle_signin_dialog_accept(detail)
  4546. {
  4547.     if (stumbleid != 0)
  4548.         su_ds.deleteStoredPassword();
  4549.     
  4550.     stumbleid = detail.userid;
  4551.     
  4552.     su_ds.setValue("@current_user", detail.userid);
  4553.     var new_profile = (! su_ds.isPrefDefined("$nick"));
  4554.     
  4555.     var unhashed_password = detail.password;
  4556.     var password = null;
  4557.     
  4558.     if (su_enable_hashed_password)
  4559.         password = su_ds.getEncodedPassword(unhashed_password, detail.userid);
  4560.     
  4561.     su_ds.storePassword(password, unhashed_password);
  4562.  
  4563.     su_ds.setValue("$autologout", detail.autologout);
  4564.     su_ds.setValue("$nick", detail.nickname);
  4565.     if(detail.thumbup_count)
  4566.     {
  4567.         su_ds.setValue("$thumbup_count", detail.thumbup_count);
  4568.         su_thumbup_count_changed();
  4569.     }
  4570.     if(detail.stumble_count)
  4571.     {
  4572.         su_ds.setValue("$stumble_count", detail.stumble_count);
  4573.         su_stumble_count_changed();
  4574.     }
  4575.     
  4576.     su_enable_client_features(detail.enableg);
  4577.     su_enable_user_features(detail.enableu);
  4578.     su_disable_client_features(detail.disableg);
  4579.     su_disable_user_features(detail.disableu);
  4580.     
  4581.     // now sync this stuff before we crash
  4582.     su_ds.flushPrefs();
  4583.  
  4584.     var login_detail = new Object();
  4585.     login_detail.skip_cookies = false;
  4586.     login_detail.ignore_cookies = true;
  4587.     login_detail.new_profile = new_profile;
  4588.     login_detail.new_user_prompt = false;
  4589.     su_invoke_global_event("login", login_detail);
  4590.     
  4591.     var loc = "discover/activity";
  4592.     su_set_server_location(loc, null, !su_is_about_blank());
  4593. }
  4594.  
  4595. // Handler for menuitem "Change Password"
  4596. function su_handle_change_password()
  4597. {
  4598.     su_unfocus_searchbox(); 
  4599.     
  4600.     var detail = new Object();
  4601.     
  4602.     detail.password = "";    
  4603.     detail.id = stumbleid;
  4604.     
  4605.     window.openDialog(
  4606.                 "chrome://stumbleupon/content/passwordDialog.xul",
  4607.                 "su_password",
  4608.                 "chrome,modal,dialog,centerscreen,dependent",
  4609.                 detail);
  4610. }
  4611.  
  4612. function su_handle_password_dialog_accept(detail)
  4613. {
  4614.     // change local password
  4615.     var unhashed_password = detail.password;
  4616.     var password = null;
  4617.     
  4618.     if (su_enable_hashed_password)
  4619.         password = su_ds.getEncodedPassword(unhashed_password, stumbleid);
  4620.     
  4621.     su_ds.storePassword(password, unhashed_password);
  4622.     
  4623.     var cookieManager = su_get_service(
  4624.                 "@mozilla.org/cookiemanager;1",
  4625.                 "nsICookieManager");
  4626.     cookieManager.remove("." + su_servername, "PHPSESSID", "/", 0);
  4627.     
  4628.     su_invoke_global_event("change-password", null);
  4629.     alert("Password changed");
  4630. }
  4631.  
  4632. // Handler for menuitem "Feedback"
  4633. function su_feedback()
  4634.  {
  4635.     if (stumbleid == 0)
  4636.         return false;
  4637.  
  4638.     // Redirect to the feedback page
  4639.     getBrowser().contentDocument.location = su_base_url + "feedback.php";
  4640.  
  4641.     return true;
  4642. }
  4643.  
  4644. // Handler for menuitem "Sign-out"
  4645. function su_handle_logout(logout_from_website)
  4646. {
  4647.     var doc = getBrowser().contentDocument;
  4648.  
  4649.     if (stumbleid == 0)
  4650.         return false;
  4651.  
  4652.     var detail = new Object();
  4653.     detail.response = 0;
  4654.     
  4655.     window.openDialog(
  4656.             "chrome://stumbleupon/content/signoutDialog.xul", 
  4657.             "su_sign_out",
  4658.             "chrome,modal,dialog,centerscreen,dependent",
  4659.             detail);
  4660.     if (detail.response == 1)
  4661.     //if (window.confirm("Are you *sure* you would like to Sign-out?\n\n(Click CANCEL if you do not know your password,\nor you will LOSE THIS ACCOUNT)"))
  4662.     {
  4663.         su_invoke_global_event("logout", null)
  4664.         if (logout_from_website)
  4665.             su_set_location("http://www." + su_servername + "/login.php?logout=1", null, null, null);
  4666.         else
  4667.         {
  4668.             var url = doc.location.toString();
  4669.             if (su_is_matching_domain(url, su_servername))
  4670.             {
  4671.                 su_set_location(url);
  4672.             }
  4673.         }
  4674.     }
  4675.  
  4676.     return true;
  4677. }
  4678.  
  4679. // handles the global login event
  4680. function su_login(skip_cookies, ignore_cookies, new_profile, new_user_prompt)
  4681. {
  4682.     if (su_stumble_async_context && su_stumble_async_context._request)
  4683.     {
  4684.         // kill the pending action
  4685.         su_service.abortPostAsync(su_stumble_async_context._request);
  4686.     }
  4687.     
  4688.     su_init_login(skip_cookies, ignore_cookies); // clears user session globals
  4689.  
  4690.     su_load_data1(new_profile);
  4691.     
  4692.     if (! new_user_prompt)
  4693.         su_ds.setValue("$intro_count", 15);
  4694.     
  4695.     if (! su_ds.getValue("~visited_signup"))
  4696.         su_show_searchlinks_dialog(new_user_prompt, false, false);
  4697.  
  4698.     su_load_data2(true);  // calls su_configure_toolbar()
  4699.     
  4700.     su_ds.setValue("~visited_signup", false);
  4701. }
  4702.  
  4703. // handles the global change-password event
  4704. function su_change_password()
  4705. {
  4706.     stumblepass = su_ds.getStoredPassword();
  4707. }
  4708.  
  4709. function su_has_logged_in()
  4710. {
  4711.     var ids = su_ds.getValue("@id_list").split(":");
  4712.  
  4713.     var found = false;
  4714.     var i;
  4715.     for (i = 0; i < ids.length; i++)
  4716.     {
  4717.         if (ids[i] == "")
  4718.             continue;
  4719.         
  4720.         found = true;
  4721.         break;
  4722.     }
  4723.     return found;
  4724. }
  4725.  
  4726. // handles the global configure-toolbar event and is used by
  4727. // load_data2()
  4728. function su_configure_toolbar(from_preference_dialog)
  4729. {
  4730.     if (! from_preference_dialog)
  4731.     {
  4732.         try {
  4733.             su_close_info();
  4734.         } catch (e) { su_log_error("CONFIGURE CLOSEINFO", e, from_preference_dialog); } 
  4735.         
  4736.         try {
  4737.             su_move_toolbar(true, 1);
  4738.         } catch (e) { su_log_error("CONFIGURE MOVE", e, from_preference_dialog, su_ds.getValue("@toolbar-position"), su_ds.getValue("@position-group")); } 
  4739.     
  4740.         try {
  4741.             su_refresh_toggle_button(true);
  4742.         } catch (e) { su_log_error("CONFIGURE TOGGLE", e, from_preference_dialog); } 
  4743.     }
  4744.         
  4745.     try {
  4746.         su_set_mode_all();
  4747.     } catch (e) { su_log_error("CONFIGURE SET MODE", e, from_preference_dialog); } 
  4748.  
  4749.     try {
  4750.         su_init_labels();
  4751.     } catch (e) { su_log_error("CONFIGURE LABELS", e, from_preference_dialog); } 
  4752.  
  4753.     try {    
  4754.         if (su_host.mac)
  4755.             su_set_attribute("su_thumbdown", "mac", "true");
  4756.     } catch (e) { su_log_error("CONFIGURE THUMBDOWN", e, from_preference_dialog); }
  4757.     
  4758.     try {
  4759.         su_init_toolbar_element_visibility();
  4760.     } catch (e) { su_log_error("CONFIGURE HIDDEN STATES", e, from_preference_dialog); } 
  4761.  
  4762.     if (stumbleid != 0)
  4763.     {
  4764.         try {
  4765.             su_set_autocomplete_type(su_ds.getValue("$autocomplete_type"));
  4766.         } catch (e) { su_log_error("CONFIGURE AUTOCOMPLETE", e, from_preference_dialog); } 
  4767.  
  4768.         try {
  4769.             su_dyn_channels_dirty = true;
  4770.             su_update_dyn_channels();
  4771.         } catch (e) { su_log_error("CONFIGURE DYN CHANNEL BUTTONS", e, from_preference_dialog); } 
  4772.  
  4773.         try {
  4774.             su_refresh_category_selector();
  4775.         } catch (e) { su_log_error("CONFIGURE CATEGORY SELECTOR", e, from_preference_dialog); } 
  4776.     
  4777.         try {
  4778.             su_referral_menu_dirty = true;
  4779.             su_update_referral_menu();
  4780.         } catch (e) { su_log_error("CONFIGURE REFERRAL MENU", e, from_preference_dialog); } 
  4781.  
  4782.         try {
  4783.             su_refresh_keybindings();
  4784.         } catch (e) { su_log_error("CONFIGURE KEYBINDINGS", e, from_preference_dialog); }
  4785.  
  4786.     }
  4787.     
  4788.     su_reflow_toolbar("CONFIGURE");
  4789.  
  4790.     setTimeout(function (win, url) { win.su_refresh_pagemeta(false, 2); }, 0, window);
  4791.     setTimeout(function (win) { win.su_reflow_toolbar("CONFIGURE2"); }, 500, window);
  4792.     setTimeout(function (win) { win.su_reflow_toolbar("CONFIGURE3"); }, 2000, window);
  4793. }
  4794.  
  4795. function su_verify_bookmarks_folder()
  4796. {
  4797.     if (! su_host.places)
  4798.         return;
  4799.     
  4800.     var bms = su_ds.getBookmarksService();
  4801.     
  4802.     var folderid = su_ds.getValue("$bm_folderid");
  4803.     var tmpidx;
  4804.     if (folderid != 0)
  4805.     {
  4806.         tmpidx = -1;
  4807.         try {
  4808.             tmpidx = bms.getItemIndex(folderid);
  4809.         } catch (e) {}
  4810.         if (tmpidx != -1)
  4811.             return;
  4812.     }
  4813.     
  4814.     var children = Application.bookmarks.menu.children;
  4815.     var i;
  4816.     var folders_by_label = new Object();
  4817.     var nonfolders_by_label = new Object();
  4818.     var item;
  4819.     for (i = 0; i < children.length; i++)
  4820.     {
  4821.         item = children[i];
  4822.  
  4823.         if ((typeof item.title) != "string")
  4824.             continue;
  4825.         
  4826.         if (item.title.indexOf("StumbleUpon") == 0)
  4827.         {
  4828.             if (item.type == "folder")
  4829.                 folders_by_label[item.title] = item;
  4830.             else
  4831.                 nonfolders_by_label[item.title] = item;
  4832.         }
  4833.     }
  4834.     
  4835.     item = null;
  4836.  
  4837.     if ((! folders_by_label["StumbleUpon"])
  4838.             && (! nonfolders_by_label["StumbleUpon"]))
  4839.     {
  4840.         item = Application.bookmarks.menu.addFolder("StumbleUpon");
  4841.     }
  4842.     
  4843.     var basename = "StumbleUpon - " + su_ds.getValue("$nick");
  4844.     var i = 1;
  4845.     var candidate_name;
  4846.     while (! item)
  4847.     {
  4848.         if (i == 1)
  4849.             candidate_name = basename;
  4850.         else
  4851.             candidate_name = basename + " (" + i + ")";
  4852.             
  4853.         if (folders_by_label[candidate_name])
  4854.             item = folders_by_label[candidate_name];
  4855.         else if (! nonfolders_by_label[candidate_name])
  4856.             item = Application.bookmarks.menu.addFolder(candidate_name);
  4857.         
  4858.         i++;
  4859.     }
  4860.     
  4861.     su_ds.setValue("$bm_folderid", item.id);
  4862.     
  4863.     su_ds.flushPrefs();
  4864. }
  4865.  
  4866. // handles the global logout event
  4867. function su_logout()
  4868. {
  4869.     // 0. If we don't hide the popup, the menu get munged
  4870.     var stumble_popup = su_get_element("su_stumble_popup");
  4871.     if (typeof(stumble_popup.hidePopup) == "function")
  4872.     {
  4873.         stumble_popup.hidePopup();
  4874.         su_unfocus();
  4875.     }
  4876.     
  4877.     if (su_stumble_async_context && su_stumble_async_context._request)
  4878.     {
  4879.         // kill the pending action
  4880.         su_service.abortPostAsync(su_stumble_async_context._request);
  4881.     }
  4882.     
  4883.     su_stumbleReporter.stop();
  4884.     
  4885.     try {    
  4886.         su_prefetcher.stop();
  4887.         su_prefetcher.clearTargets();
  4888.     } catch (e) { su_log_error("PREFETCHER 4", e); }
  4889.     
  4890.     try {
  4891.         su_close_all_messages();
  4892.     } catch (e) { su_log_error("LOGOUT CLOSEALLMSGS", e); }
  4893.     
  4894.     su_logout_auth(); // clears user session globals
  4895.  
  4896.     su_init_labels();
  4897.     
  4898.     su_init_toolbar_element_visibility();
  4899.     
  4900.     su_refresh_pagemeta(false, 5);
  4901.  
  4902.     su_get_element("su_stumble").setAttribute("image2", "");
  4903.     
  4904.     setTimeout(su_reflow_toolbar, 0, 2);
  4905.  
  4906.     su_commands_by_keyspec = new Object();
  4907.  
  4908.     window.removeEventListener("keyup", su_handle_window_keyup, false);
  4909.     window.removeEventListener("keypress", su_handle_window_keypress, false);
  4910.  
  4911.     var toggle_key = su_get_element("key_StumbleUpon:ToggleToolbar");
  4912.     if (toggle_key)
  4913.         toggle_key.setAttribute("command", toggle_key.getAttribute("savedcommand"));
  4914.  
  4915.     var toolbar_el = su_get_element("stumbleupon");
  4916.     if (toolbar_el)
  4917.         toolbar_el.setAttribute("toolbarname", toolbar_el.getAttribute("savedtoolbarname"));
  4918.     
  4919. }
  4920.  
  4921. // handles the Extension Manager uninstall event in Firefox 1.5+; 
  4922. // prompts for uninstallation options
  4923. function su_handle_em_uninstall()
  4924. {
  4925.     su_uninstall_scheduled = true;
  4926.  
  4927.     var recent_window = su_get_service(
  4928.                 "@mozilla.org/appshell/window-mediator;1",
  4929.                 "nsIWindowMediator")
  4930.                 .getMostRecentWindow("navigator:browser");
  4931.  
  4932.     if (window != recent_window)
  4933.         return;
  4934.     
  4935.     var detail = new Object();
  4936.     detail.logout = false;
  4937.     detail.remove_data = false;
  4938.     detail.delete_account = false;
  4939.  
  4940.     su_unfocus_searchbox(); 
  4941.  
  4942.     window.openDialog(
  4943.                 "chrome://stumbleupon/content/uninstallDialog.xul",
  4944.                 "su_uninstall_options",
  4945.                 "chrome,modal,dialog,centerscreen,dependent", 
  4946.                 detail);
  4947.                 
  4948.     if (detail.delete_account)
  4949.     {
  4950.         if (su_enable_hashed_password)
  4951.         {
  4952.             su_post_url_server(
  4953.                         "delete_account.php",
  4954.                         "version=" + su_verstring + 
  4955.                             "&stumbler=" + stumbleid + 
  4956.                             "&password=" + stumblepass);
  4957.         }
  4958.         else
  4959.         {
  4960.             su_post_url_server(
  4961.                         "delete_account.php",
  4962.                         "version=" + su_verstring + 
  4963.                             "&stumbler=" + stumbleid + 
  4964.                             "&password=" + encodeURIComponent(stumblepass));
  4965.         }
  4966.     }
  4967.  
  4968.     if (detail.logout)
  4969.         su_invoke_global_event("logout", null);
  4970.     
  4971.     if (detail.remove_data)
  4972.         su_invoke_global_event("schedule-remove-data", null);
  4973. }
  4974.  
  4975.  
  4976. // handles the global schedule-remove-data event
  4977. function su_schedule_remove_data()
  4978. {
  4979.     // We remove the data now for good measure, then we remove it again
  4980.     // when each window is closed and when the app quits. -- JW
  4981.     su_remove_data_scheduled = true;
  4982.     su_remove_data();
  4983. }
  4984.  
  4985. // removes all stumbleupon files and preferences
  4986. function su_remove_data()
  4987. {
  4988.     var ids = new Array();
  4989.     try {
  4990.         ids = su_ds.getValue("@id_list").split(":");
  4991.     } catch (e) {}
  4992.     var i;
  4993.     for (i = 0; i < ids.length; i++)
  4994.     {
  4995.         if (ids[i] == "")
  4996.             continue;
  4997.         
  4998.         su_ds.deleteFile(su_ds.getLegacyNSIFile("stumbleurls", ids[i]));
  4999.         su_ds.deleteFile(su_ds.getLegacyNSIFile("stumblerating", ids[i]));
  5000.         su_ds.deleteFile(su_ds.getLegacyNSIFile("stumbletags", ids[i]));
  5001.         su_ds.deleteFile(su_ds.getLegacyNSIFile("stumblequeries", ids[i]));
  5002.     }
  5003.  
  5004.     var file = su_get_service(
  5005.                 "@mozilla.org/file/directory_service;1",
  5006.                 "nsIProperties")
  5007.                 .get("ProfD", Components.interfaces.nsIFile);
  5008.     file.append("StumbleUpon");
  5009.     su_ds.deleteDirectory(file);
  5010.     
  5011.     var pref_names = su_ds.getPrefNames("stumble.");
  5012.     for (i = 0; i < pref_names.length; i++)
  5013.     {
  5014.         try {
  5015.             su_ds.clearPref(pref_names[i]);
  5016.         } catch (e) {}
  5017.     }
  5018.  
  5019.     var cookieManager = su_get_service(
  5020.             "@mozilla.org/cookiemanager;1",
  5021.             "nsICookieManager");
  5022.     cookieManager.remove("." + su_servername, "PHPSESSID", "/", 0);
  5023.     cookieManager.remove("." + su_servername, "stumble_user", "/", 0);
  5024.     cookieManager.remove("." + su_servername, "stumble_pass", "/", 0);
  5025.     cookieManager.remove("." + su_servername, "tsuu", "/", 0);
  5026.     cookieManager.remove("." + su_servername, "tsut", "/", 0);
  5027.     cookieManager.remove("." + su_servername, "nickname", "/", 0);
  5028.     cookieManager.remove("." + su_servername, "searchlinks", "/", 0);
  5029.     cookieManager.remove("." + su_servername, "thru_domains", "/", 0);
  5030.     cookieManager.remove("." + su_servername, "enableu", "/", 0);
  5031.     cookieManager.remove("." + su_servername, "enableg", "/", 0);
  5032.     cookieManager.remove("." + su_servername, "SU_REMEMBER", "/", 0);
  5033.     
  5034.     su_logout_server();
  5035. }
  5036.  
  5037. // Handler for menuitem "Chatroom"
  5038. function su_chat()
  5039. {
  5040.     var doc = getBrowser().contentDocument;
  5041.  
  5042.     if (stumbleid == 0)
  5043.         return;
  5044.  
  5045.     // Redirect to the chat page
  5046.     getBrowser().contentDocument.location = su_base_url + "chat.php";
  5047. }
  5048.  
  5049. // Handler for button "FirstRater" (the happy face)
  5050. function firstrater_func(event)
  5051. {
  5052.     var doc = getBrowser().contentDocument;
  5053.  
  5054.     if (stumbleid == 0)
  5055.         return;
  5056.  
  5057.     var frater = su_get_element("firstrater");
  5058.     var firstrater = frater.firstrater;
  5059.  
  5060.     su_set_location(
  5061.                 "http://" + firstrater + "." + su_servername + "/",
  5062.                 null,
  5063.                 su_new_tab(event));
  5064. }
  5065.  
  5066. // sets the tabbrowser location, to one of the user's profile tabs
  5067. function su_set_profile_location(profile_tab, new_tab)
  5068. {
  5069.     var nick = su_ds.getValue("$nick");
  5070.  
  5071.     var go_url = '';
  5072.     if (nick == '')
  5073.         go_url = "http://" + stumbleid + "." + su_servername + "/";
  5074.     else
  5075.         go_url = "http://" + nick + "." + su_servername + "/";        
  5076.  
  5077.     if (profile_tab != '')
  5078.         go_url += profile_tab + "/";
  5079.  
  5080.     su_set_location(go_url, null, new_tab);
  5081. }
  5082.  
  5083. // sets the tabbrowser location, when the location is beneath the 
  5084. // www stumbleupon domain
  5085. function su_set_server_location(url_suffix, postdata, new_tab)
  5086. {
  5087.     su_set_location(su_base_url + url_suffix, postdata, new_tab, null)
  5088. }
  5089.  
  5090. function su_set_server_location_signup(new_tab)
  5091. {
  5092.     var params = "";
  5093.     var loc = "signup.php";
  5094.     if (su_host.dist)
  5095.         loc = "sign_up.php";
  5096.     
  5097.     params = su_arp(params, "version", su_useragent);
  5098.     
  5099.     if (su_host.dist)
  5100.         loc = su_arp(loc, "dist", su_host.dist, true);
  5101.     
  5102.     if (su_ds.getValue("@facebook_user"))
  5103.         loc = su_arp(loc, "pre", "facebook", true);
  5104.     
  5105.     su_set_server_location(
  5106.                 loc,
  5107.                 params,
  5108.                 new_tab);        
  5109. }
  5110.  
  5111. // sets the tabbrowser location
  5112. function su_set_location(uri, postdata, new_tab, opt_detail)
  5113. {
  5114.     if ((typeof opt_detail) == "undefined")
  5115.         opt_detail = null;
  5116.     
  5117.     var browser = getBrowser();
  5118.     if (new_tab)
  5119.     {
  5120.         var tab = browser.addTab(
  5121.                     uri,
  5122.                     su_get_nsiuri(browser.contentDocument.referrer),
  5123.                     null, // charset
  5124.                     (postdata == null) ? null : su_get_mime_input_stream(postdata, "application/x-www-form-urlencoded"));
  5125.         browser.selectedTab = tab;
  5126.         
  5127.         tab.su_detail = opt_detail;
  5128.     }
  5129.     else
  5130.     {
  5131.         browser.selectedTab.su_detail = opt_detail;
  5132.         
  5133.         browser.webNavigation.loadURI(
  5134.                     uri,
  5135.                     Components.interfaces.nsIWebNavigation.LOAD_FLAGS_NONE,
  5136.                     su_get_nsiuri(browser.contentDocument.referrer),
  5137.                     (postdata == null) ? null : su_get_mime_input_stream(postdata, "application/x-www-form-urlencoded"),
  5138.                     null); // headers
  5139.     }
  5140. }
  5141.  
  5142. // Handler for button "Website Info"
  5143. function su_website_info(new_tab, theurl, firstrate)
  5144. {
  5145.     
  5146.     if (su_ds.getValue("$review_new_window"))
  5147.         new_tab = true;
  5148.  
  5149.     if (stumbleid == 0)
  5150.         return;
  5151.  
  5152.     var current_page = theurl;
  5153.     
  5154.     if (theurl == "")
  5155.     {
  5156.         current_page = su_get_browser_url();        
  5157.         if (stumbled_redirect != '' && current_page == stumbled_redirect)
  5158.         {
  5159.             // we have a redirect, rate the original url we stumbled on
  5160.             current_page = stumbled_url;
  5161.         }        
  5162.     }
  5163.     
  5164.     var cmp_url = current_page.toLowerCase();
  5165.     
  5166.     if (cmp_url.indexOf("http://video." + su_servername + "/#p") == 0)
  5167.         return;
  5168.                 
  5169.     if (cmp_url.indexOf("http://video." + su_servername + "/?p") == 0)
  5170.         return;
  5171.     
  5172.     var stumblevideo = (su_get_stumblevideo_detail() != null);
  5173.     
  5174.     if (current_page.indexOf("about:") == 0)
  5175.         return;
  5176.     
  5177.     if ((su_quote == "") && getBrowser().contentWindow.getSelection)
  5178.     {
  5179.         quote = getBrowser().contentWindow.getSelection().toString();
  5180.     }
  5181.     else
  5182.     {
  5183.         quote = su_quote;
  5184.         su_quote = "";
  5185.     }
  5186.     
  5187.     var searchbox_value = su_get_element("su_searchbox").value;
  5188.     if ((! su_ds.getValue("$show_field")) || 
  5189.                 (searchbox_value == su_tag_instructions) ||
  5190.                 su_validate_tagstring(searchbox_value))
  5191.     {
  5192.         searchbox_value = "";
  5193.     }
  5194.     
  5195.     var current_page2 = current_page;
  5196.     if (current_page2.length > 300)
  5197.         current_page2 = current_page2.substr(0, 300);
  5198.  
  5199.     if ((! stumblevideo) && su_photoblogimage)
  5200.     {
  5201.         su_set_server_location(
  5202.                     "url.php?url=" + encodeURIComponent(current_page2) + 
  5203.                         "&image=" + encodeURIComponent(su_photoblogimage.src) + 
  5204.                         "&width=" + su_photoblogimage.width + 
  5205.                         "&height=" + su_photoblogimage.height + 
  5206.                         "&firstrate=" + firstrate + 
  5207.                         "&tag=" + escape(searchbox_value),
  5208.                     null,
  5209.                     new_tab);
  5210.         su_photoblogimage = null;
  5211.     }
  5212.     else if ((! stumblevideo) && (quote != ""))
  5213.     {
  5214.         su_set_server_location(
  5215.                     "url.php?url=" + encodeURIComponent(current_page2) + 
  5216.                         ""e=" + encodeURIComponent(quote) + 
  5217.                         "&firstrate=" + firstrate + 
  5218.                         "&tag=" + escape(searchbox_value), 
  5219.                     null,
  5220.                     new_tab);
  5221.     }
  5222.     else
  5223.     {
  5224.         su_set_server_location(
  5225.                     "url/" + su_review_url(current_page),
  5226.                     null,
  5227.                     new_tab);
  5228. //        setTimeout(
  5229. //                    su_set_server_location,
  5230. //                    3000,
  5231. //                    "url/" + su_review_url(current_page, true),
  5232. //                    null,
  5233. //                    new_tab);
  5234.     }
  5235. }
  5236.  
  5237. function su_review_url(url, new_impl)
  5238. {
  5239.     // strip off the http://
  5240.     if (url.match(/^http:\/\//i))
  5241.         url = url.substr(7);
  5242.     
  5243.     url = encodeURIComponent(url);
  5244.     
  5245.     url = encodeURIComponent(url);
  5246.  
  5247.     url = url.replace(/%252F/g, "/");
  5248.  
  5249.     return url;
  5250. }
  5251.  
  5252. // Check to see if an email is valid
  5253. function su_validate_email(str)
  5254. {
  5255.     // var filter=/^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
  5256.     var filter  = /^([a-zA-Z0-9_\.\-+])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
  5257.     if (filter.test(str))
  5258.         return(true);
  5259.     else
  5260.         return(false);
  5261. }
  5262.  
  5263. function su_remove_email(email)
  5264. {
  5265.     if (!(window.confirm("Are you sure that you want to delete the email address '" + email + "'")))
  5266.         return;
  5267.  
  5268.     var contact = su_ds.selectRow("contact", "email", email);
  5269.     
  5270.     if (! contact)
  5271.         return;
  5272.     
  5273.     contact.hidden = true;
  5274.     su_ds.updateRow(contact);
  5275.     su_ds.flushPrefs();
  5276.     
  5277.     su_refresh_referral_menu(2);
  5278. }
  5279.  
  5280. // Handler for menuitem from mailto menu
  5281. function su_mailit(recipient_email)
  5282. {
  5283.     if (stumbleid == 0)
  5284.         return;
  5285.  
  5286.     su_unfocus_searchbox(); 
  5287.     // Now grab recipient and cache it
  5288.     if (recipient_email == "")
  5289.     {
  5290.         recipient_email = getBrowser().contentWindow.prompt("Please enter the recipient's email address", "");
  5291.         if (recipient_email == null || recipient_email == "" || typeof(recipient_email) == "undefined")
  5292.             return;
  5293.     }
  5294.  
  5295.     // do an email sanity check
  5296.     if (!su_validate_email(recipient_email))
  5297.     {
  5298.         alert("Recipient is not a valid email address!");
  5299.         return;
  5300.     }
  5301.  
  5302.     // Cache the email
  5303.     var contact = su_ds.selectRow("contact", "email", recipient_email);
  5304.     
  5305.     if (contact && contact.hidden)
  5306.     {
  5307.         contact.hidden = false;
  5308.         su_ds.updateRow(contact);
  5309.     }
  5310.     else if (! contact)
  5311.     {
  5312.         contact = new Object();
  5313.         contact.email = recipient_email;
  5314.         su_ds.insertRow("contact", contact);
  5315.     }
  5316.  
  5317.     su_ds.flushPrefs();    
  5318.  
  5319.     var current_page = su_get_browser_url();
  5320.     
  5321.     if (current_page.indexOf("about:") == 0)
  5322.     {    
  5323.         su_refresh_referral_menu(3);
  5324.         return;
  5325.     }
  5326.  
  5327.     su_unfocus_searchbox(); 
  5328.  
  5329.     
  5330.     var detail = new Object();
  5331.     detail.mode = "email";
  5332.     detail.target = recipient_email;
  5333.     detail.url = current_page;
  5334.     detail.display_url = su_get_browser_url(null, true);
  5335.     detail.stumblevideo = (su_get_stumblevideo_detail() != null);
  5336.     detail.title = getBrowser().contentDocument.title;
  5337.     detail.dialog_title = "Send to " + detail.target;
  5338.     detail.show_target = su_host.mac;
  5339.     detail.referrer_url = su_get_browser_referrer_url();
  5340.  
  5341.     window.openDialog(
  5342.                 "chrome://stumbleupon/content/sendDialog.xul",
  5343.                 "",
  5344.                 "chrome,dialog,centerscreen,dependent", 
  5345.                 detail);
  5346. }
  5347.  
  5348. function su_generic_done(res)
  5349. {
  5350.     var context = res.detail;
  5351.     
  5352.     try {
  5353.         if (res.status != 200)
  5354.             return;
  5355.     } catch (e) { return; } 
  5356.     
  5357.     var s = "";
  5358.     if (typeof(res.responseText) != "undefined")
  5359.         s = res.responseText;
  5360.     
  5361.     if (su_log_communication)
  5362.         su_log("response " + context.request_target, s);
  5363.     
  5364.     su_process_commands(s, context);
  5365. }
  5366.  
  5367. // TODO:  I suspect this completion method should be used in more places, but we are 
  5368. //        too close to a release right now to touch too many code paths.  Note that this
  5369. //        is the same code in stumble done, so at least those two should be combined. 
  5370. //
  5371. function su_verbose_generic_done(res)
  5372. {
  5373.     var context = res.detail;
  5374.     res.done = true;
  5375.     
  5376.     try {
  5377.         if (res.status != 200)
  5378.         {
  5379.             // Maintenance mode returns 503 with "ERROR xxx" set.
  5380.             // In that case, let the "ERROR" command be handled.
  5381.             var isMaintenanceMode = false;
  5382.             if(res.status == 503)
  5383.             {
  5384.                 var commands = res.responseText.split(" ");
  5385.                 if(commands.length && (commands[0] == "ERROR"))
  5386.                 {
  5387.                     // Let it fall through 
  5388.                     isMaintenanceMode = true;
  5389.                 }
  5390.             }
  5391.             if(!isMaintenanceMode)
  5392.             {
  5393.                 if (! context.quiet)
  5394.                     alert("The stumbleupon.com server is currently down.\nPlease try again, and if you are still having difficulties,\ngo to "
  5395.                         + su_base_url + "feedback.php to report the problem\nError : " + res.error + "\nStatus : " + res.status);
  5396.                 if (callback)
  5397.                     callback("connection error", ancestor_callback, context);
  5398.                 return;
  5399.             }
  5400.         }
  5401.     } catch (e) { return; } 
  5402.     
  5403.     var s = "";
  5404.     if (typeof(res.responseText) != "undefined")
  5405.         s = res.responseText;
  5406.     
  5407.     if (su_log_communication)
  5408.         su_log("response " + context.request_target, s);
  5409.     
  5410.     su_process_commands(s, context);
  5411. }
  5412.  
  5413.  
  5414. // Handler for menuitem "About"
  5415. function su_about()
  5416. {
  5417.     // Redirect to about page
  5418.     getBrowser().contentDocument.location = su_serverhttp + 'about.php?version=' + su_verstring;
  5419. }
  5420.  
  5421. function su_get_friends()
  5422. {
  5423.     var params = "";
  5424.     params = su_arp(params, "now", su_get_time_s());
  5425.     params = su_arp(params, "configured", su_ds.getValue("$friends_synced"));
  5426.     
  5427.     su_post_url_server_async(
  5428.                 "getfriends.php",
  5429.                 params,
  5430.                 null,
  5431.                 su_get_friends_done,
  5432.                 null);
  5433. }
  5434.  
  5435. function su_get_friends_done(res)
  5436. {
  5437.     try {
  5438.         if (res.status != 200)
  5439.             return;
  5440.     } catch (e) { return; } 
  5441.     
  5442.     var s = "";
  5443.     if (typeof(res.responseText) != "undefined")
  5444.         s = res.responseText;
  5445.     
  5446.     if (su_log_communication)
  5447.         su_log("response getfriends.php", s);
  5448.     
  5449.     var context = new Object();
  5450.     context.quiet = true;
  5451.     su_process_commands(s, context);
  5452.     
  5453.     su_ds.setValue("$friends_synced", "" + su_get_time_s());
  5454. }
  5455.  
  5456. function su_get_facebook_userid()
  5457. {
  5458.     var fbuserid = su_ds.getValue("#facebook_userid"); 
  5459.     if (fbuserid)
  5460.         return fbuserid;
  5461.     
  5462.     var manager = su_get_service(
  5463.                 "@mozilla.org/cookiemanager;1",
  5464.                 "nsICookieManager");
  5465.     var cookies = manager.enumerator;
  5466.     var cookie;
  5467.     
  5468.     while (cookies.hasMoreElements())
  5469.     {
  5470.         cookie = cookies.getNext().QueryInterface(
  5471.                     Components.interfaces.nsICookie);
  5472.                     
  5473.         if (cookie.host == ".facebook.com")
  5474.         {
  5475.             if (cookie.name == "c_user")
  5476.             {
  5477.                 fbuserid = parseInt(cookie.value);
  5478.                 break;
  5479.             }
  5480.         }
  5481.     }
  5482.     su_ds.setValue("#facebook_userid", fbuserid);
  5483.     return fbuserid;
  5484. }
  5485.  
  5486. function su_get_facebook(doc)
  5487. {
  5488.     if (stumbleid == 0)
  5489.         return;
  5490.     
  5491.     if (su_ds.getValue("#checking_facebook"))
  5492.         return;
  5493.     
  5494.     su_ds.setValue("#checking_facebook", true);
  5495.     
  5496.     var detail = new Object();
  5497.     detail.doc = doc;
  5498.     detail.stumbleid = stumbleid;
  5499.     
  5500.     var fbuserid = su_get_facebook_userid();
  5501.     
  5502.     if (! fbuserid)
  5503.     {
  5504.         su_ds.setValue("#checking_facebook", false);
  5505.         return;
  5506.     }
  5507.     
  5508.     su_post_url_server_async(
  5509.                 "getfacebook.php",
  5510.                 su_arp("", "id", fbuserid),
  5511.                 15000,
  5512.                 su_get_facebook_done,
  5513.                 detail);
  5514. }
  5515.  
  5516. function su_get_facebook_done(res)
  5517. {
  5518.     try {
  5519.         if (res.status != 200)
  5520.             return;
  5521.     } catch (e) { return; } 
  5522.     
  5523.     var s = "";
  5524.     if (typeof(res.responseText) != "undefined")
  5525.         s = res.responseText;
  5526.     
  5527.     var detail = res.detail;
  5528.     
  5529.     if (su_log_communication)
  5530.         su_log("response getfacebook.php", s);
  5531.     
  5532.     if (detail.stumbleid != stumbleid)
  5533.         return;
  5534.     
  5535.     su_ds.setValue("#checking_facebook", false);    
  5536.     
  5537.     if (! res.aborted)
  5538.         su_ds.setValue("#checked_facebook", true);
  5539.     
  5540.     var context = new Object();
  5541.     context.quiet = true;
  5542.     su_process_commands(s, context);
  5543.     
  5544.     su_refresh_pagemeta(false, 6);
  5545.     
  5546.     if (detail.doc)
  5547.         su_facebookhome_page(detail.doc);
  5548. }
  5549.  
  5550. function su_get_state(migrating)
  5551. {
  5552.     su_post_url_server_async(
  5553.                 "getstate.php",
  5554.                 su_arp("", "migrating", ((migrating) ? 1 : 0)),
  5555.                 null,
  5556.                 su_get_state_done,
  5557.                 null);
  5558. }
  5559.  
  5560. function su_get_state_done(res)
  5561. {
  5562.     try {
  5563.         if (res.status != 200)
  5564.             return;
  5565.     } catch (e) { return; } 
  5566.     
  5567.     var s = "";
  5568.     if (typeof(res.responseText) != "undefined")
  5569.         s = res.responseText;
  5570.     
  5571.     if (su_log_communication)
  5572.         su_log("response getstate.php", s);
  5573.     
  5574.     var context = new Object();
  5575.     context.quiet = true;
  5576.     su_process_commands(s, context, true, 0);
  5577. }
  5578.  
  5579. function su_import_contacts()
  5580. {
  5581.     // hit getcontacts.php, parse, and add non-dupes to menu    
  5582.     su_post_url_server_async(
  5583.                 "getcontacts.php",
  5584.                 null,
  5585.                 null,
  5586.                 su_import_contacts_done,
  5587.                 null);
  5588. }
  5589.  
  5590. function su_import_contacts_done(res)
  5591. {
  5592.     try {
  5593.         if (res.status == 1)
  5594.             return;
  5595.     } catch (e) { return; }
  5596.  
  5597.     if (res.status != 200)
  5598.         return;
  5599.     
  5600.     var s = res.responseText;
  5601.  
  5602.     if (typeof(s) != "object" && typeof(s) != "undefined" && s != "")
  5603.     {
  5604.         var newlines = s.split("\n");
  5605.         for (var i = 0; i < newlines.length; i++)
  5606.         {
  5607.             if (newlines[i] == "")
  5608.                 continue;
  5609.             
  5610.             var lines = newlines[i].split(",");
  5611.             if (lines.length>0)
  5612.             {
  5613.                 var email = lines[0];
  5614.  
  5615.                 //invalid email address
  5616.                 if (!su_validate_email(email))
  5617.                     continue;
  5618.                 
  5619.                 var contact = su_ds.selectRow("contact", "email", email);
  5620.                 if (! contact)
  5621.                 {
  5622.                     contact = new Object();
  5623.                     contact.email = email;
  5624.                     su_ds.insertRow("contact", contact);
  5625.                 }
  5626.             }
  5627.         }
  5628.         su_ds.flushPrefs();
  5629.         su_refresh_referral_menu(4);    
  5630.     }
  5631. }
  5632.  
  5633. function su_get_interests()
  5634. {
  5635.     su_post_url_server_async(
  5636.                 "getinterests.php",
  5637.                 null,
  5638.                 null,
  5639.                 su_get_interests_done,
  5640.                 null);
  5641. }
  5642.  
  5643. function su_get_interests_done(res)
  5644. {
  5645.     try {
  5646.         if (res.status != 200)
  5647.             return;
  5648.     } catch (e) { return; } 
  5649.     
  5650.     var s = "";
  5651.     
  5652.     if (typeof(res.responseText) != "undefined")
  5653.         s = res.responseText;
  5654.     
  5655.     if (su_log_communication)
  5656.         su_log("response getinterests.php", s);
  5657.     
  5658.     if (typeof(s) != "string")
  5659.         return;
  5660.         
  5661.     su_process_topic_list(s);
  5662. }
  5663.  
  5664. function su_dist_time()
  5665. {
  5666.     var now = su_get_time_s();
  5667.     var installed = su_ds.getIntValue("@installed");
  5668.     if (installed == 0)
  5669.     {
  5670.         installed = now;
  5671.         su_ds.setValue("@installed", "" + now);
  5672.     }
  5673.     
  5674.     if (! su_host.dist)
  5675.         return;
  5676.     
  5677.     if (su_dist_time_timer)
  5678.     {
  5679.         // if the user changes, this clears the timeout set for the
  5680.         // previously logged in user
  5681.         clearTimeout(su_dist_time_timer);
  5682.     }
  5683.     
  5684.     var reg_prev = su_ds.getIntValue("@dist_reg");
  5685.     var interval = 7 * 24 * 60 * 60 * 1000;
  5686.     var id_list_prev = su_ds.getValue("@dist_id_list");  
  5687.     var id_list = su_ds.getValue("@id_list");
  5688.     if ((reg_prev < (now - interval)) && ((id_list_prev == "") || 
  5689.                 (id_list_prev != id_list)))
  5690.     {
  5691.         su_ds.setValue("@dist_reg", "" + now);
  5692.         
  5693.         var params = "";
  5694.         params = su_arp(params, "dist", su_host.dist);
  5695.         params = su_arp(params, "regid", su_ds.getValue("@dist_regid")); 
  5696.         params = su_arp(params, "idlist", id_list); 
  5697.         params = su_arp(params, "preidlist", id_list_prev);
  5698.         params = su_arp(params, "age", (now - installed));
  5699.         params = su_arp(params, "visible", 
  5700.                     (su_ds.getValue("@toolbar-visible")) ? 1 : 0);
  5701.         su_post_url_server_async(
  5702.                     "disttime.php",
  5703.                     params,
  5704.                     null,
  5705.                     su_dist_time_done,
  5706.                     null);
  5707.     }
  5708.  
  5709.     su_dist_time_timer = setTimeout(su_dist_time, interval - (su_random_delay * 1000));
  5710. }
  5711.  
  5712. function su_dist_time_done(res)
  5713. {
  5714.     try {
  5715.         if (res.status != 200)
  5716.             return;
  5717.     } catch (e) { return; } 
  5718.     
  5719.     su_ds.setValue("@dist_id_list", su_ds.getValue("@id_list"));
  5720.     
  5721.     var s = "";
  5722.     if (typeof(res.responseText) != "undefined")
  5723.         s = res.responseText;
  5724.     
  5725.     if (su_log_communication)
  5726.         su_log("response disttime.php", s);
  5727.  
  5728.     var context = new Object();
  5729.     context.quiet = true;
  5730.     su_process_commands(s, context);
  5731. }
  5732.  
  5733. //
  5734. // After a certain period of idle stumble activity, we want to reset
  5735. // the stumble category back to "All".  This takes care of preventing users from
  5736. // unknowingly being stuck in a category.
  5737. //
  5738. function su_test_category_reset()
  5739. {
  5740.     var last_stumbled = su_ds.getIntValue("$last_stumble");
  5741.     if(su_selected_category == "0")
  5742.     {
  5743.         // We are already in "all"
  5744.         return;
  5745.     }
  5746.     
  5747.     var last_stumbled = su_ds.getIntValue("$last_stumble");
  5748.     var category_reset_timeout = su_ds.getValue("@category_reset_timeout");
  5749.     var timenow = (new Date()).getTime();
  5750.     
  5751.     var diff = timenow - last_stumbled;
  5752.     if(diff >= category_reset_timeout)
  5753.     {
  5754.         su_set_mode_all();
  5755.     }
  5756. }
  5757.  
  5758. function su_process_quarter_hourly()
  5759. {
  5760.     su_test_category_reset();
  5761. }
  5762.  
  5763. function su_process_rarely(force_dyn_channels, timeout)
  5764. {
  5765.     if (su_process_rarely_timer)
  5766.     {
  5767.         // if the user changes, this clears the timeout set for the
  5768.         // previously logged in user
  5769.         clearTimeout(su_process_rarely_timer);
  5770.     }
  5771.     var old_timestamp = su_ds.getIntValue("$process_rarely_timestamp");
  5772.     var last_stumbled = su_ds.getIntValue("$last_stumble");
  5773.     
  5774.     var timenow = (new Date()).getTime();
  5775.     
  5776.     var interval = 48 * 60 * 60 * 1000; // two days
  5777.     var oneweek = 7 * 24 * 60 * 60 * 1000;
  5778.     
  5779.     su_process_slclicks(timeout);
  5780.     
  5781.     if (force_dyn_channels)
  5782.     {
  5783.         su_ds.setValue("$process_rarely_timestamp", timenow);
  5784.         su_check_dyn_channels();
  5785.     }
  5786.     else if ( ((timenow - old_timestamp) > interval) && 
  5787.                 ((timenow - last_stumbled) < (8 * oneweek)) )
  5788.     {
  5789.         su_ds.setValue("$process_rarely_timestamp", timenow);
  5790.         // Routines here run every second day unless the user hasn't 
  5791.         // stumbled for two months. -- JW
  5792.         su_check_dyn_channels();
  5793.     }
  5794.     su_process_rarely_timer = setTimeout(su_process_rarely, interval - (su_random_delay * 1000), false, true);
  5795. }
  5796.  
  5797. function su_check_dyn_channels()
  5798. {
  5799.     var url = "http://cdn.stumble-upon.com/stumblethru.csv";
  5800.     
  5801.     if (su_test_stumblethru_update)
  5802.         url = su_serverhttp + "stumblethru.csv";
  5803.     
  5804.     su_ds.setValue("#checked_dyn_channels", true);
  5805.     su_post_url_async(
  5806.                 url,
  5807.                 null,
  5808.                 null,
  5809.                 su_check_dyn_channels_done,
  5810.                 null);
  5811. }
  5812.  
  5813. function su_check_dyn_channels_done(res)
  5814. {
  5815.     try {
  5816.         if (res.status != 200)
  5817.             return;
  5818.     } catch (e) { return; } 
  5819.     
  5820.     var s = "";
  5821.     if (typeof(res.responseText) != "undefined")
  5822.         s = res.responseText;
  5823.  
  5824.     if (su_log_communication)
  5825.         su_log("response stumblethru.csv", s);
  5826.  
  5827.     if (su_ds.getValue("#installing_favicons"))
  5828.         return;
  5829.     
  5830.     su_ds.setValue("#installing_favicons", true);
  5831.     
  5832.     // Parse response text
  5833.     var items = s.split("\n");
  5834.  
  5835.     var default_domain_list = su_ds.getValue("$default_thru_domain_list");
  5836.     var default_domain_flags = new Object();
  5837.     if (default_domain_list != "")
  5838.     {
  5839.         var domains = default_domain_list.split(" ");
  5840.         for (i = 0; i < domains.length; i++)
  5841.             default_domain_flags[domains[i]] = 1;
  5842.     }
  5843.     
  5844.     var i;
  5845.  
  5846.     var j;
  5847.     var channel;
  5848.     var good_channels = new Object(); 
  5849.     var has_favicons = su_ds.getValue("$has_favicons");
  5850.     
  5851.     var checked_sanity = false;
  5852.     
  5853.     for (i = 0; i < items.length; i++)
  5854.     {
  5855.         if (items[i] == "")
  5856.             continue;
  5857.         
  5858.         // do a sanity check on the first nonempty row
  5859.         if (! checked_sanity)
  5860.         {
  5861.             checked_sanity = true;
  5862.             if (! items[i].match(/^.*\..*,\d+,/))
  5863.                 return;
  5864.         }
  5865.         
  5866.         var domain = items[i].split(",")[0];
  5867.         var name = items[i].split(",")[2];
  5868.         good_channels[domain] = 1;
  5869.         
  5870.         channel = su_ds.getThruDomainChannel(domain);
  5871.         
  5872.         var filename = su_get_channel_id(domain) + ".ico";
  5873.         var url = "http://cdn.stumble-upon.com/images/stumblethru/" + filename;
  5874.         if (su_test_stumblethru_update)
  5875.             url = su_serverhttp + "images/stumblethru/" + filename;
  5876.         if (channel)
  5877.         {
  5878.             channel.name = name;
  5879.             su_ds.updateRow(channel);
  5880.             if ((! has_favicons) || (! su_ds.isResourceInstalled("favicons", filename)))
  5881.             {
  5882.                 su_ds.installResource(
  5883.                         url,
  5884.                         "favicons",
  5885.                         filename);
  5886.             }
  5887.         }
  5888.         else
  5889.         {
  5890.             channel = new Object();
  5891.             channel.domain = domain;
  5892.             channel.name = name;
  5893.             if (default_domain_flags[domain])
  5894.                 channel.show = 1;
  5895.             su_ds.installResource(
  5896.                     url,
  5897.                     "favicons",
  5898.                     filename);
  5899.             su_ds.insertRow("dyn_channel", channel);
  5900.         }
  5901.     }
  5902.     
  5903.     var channels = su_ds.getThruDomainChannels(false);
  5904.     for (i = 0; i < channels.length; i++)
  5905.     {
  5906.         if (! good_channels[channels[i].domain])
  5907.             su_ds.deleteRow(channels[i]);
  5908.     }
  5909. }
  5910.  
  5911. function su_sync(context)
  5912. {
  5913.     if (su_get_time_s() < su_ds.getIntValue("$sync_retry_time_s"))
  5914.         return;
  5915.     
  5916.     var params = "";
  5917.     
  5918.     params = su_append_sync_params(params);
  5919.     
  5920.     var context = new Object();
  5921.     context.quiet = true;
  5922.     context.from_sync = true;
  5923.     
  5924.     su_post_url_server_async(
  5925.                 "sync.php",
  5926.                 params,
  5927.                 15000,
  5928.                 su_sync_done,
  5929.                 context);
  5930. }
  5931.  
  5932. function su_append_sync_params(params)
  5933. {
  5934.     params = su_arp(params, "ycur_q", su_ds.getValue("$sync_cur_q"));
  5935.     params = su_arp(params, "ycur_t", su_ds.getValue("$sync_cur_t"));
  5936.     params = su_arp(params, "ycur_s", su_ds.getValue("$sync_cur_s"));
  5937.     params = su_arp(params, "ypre_q", su_ds.getValue("$sync_pre_q"));
  5938.     params = su_arp(params, "ypre_t", su_ds.getValue("$sync_pre_t"));
  5939.     params = su_arp(params, "ypre_s", su_ds.getValue("$sync_pre_s"));
  5940.     params = su_arp(params, "yr", su_ds.getValue("$sync_retry"));
  5941.     params = su_arp(params, "yts", su_ds.getValue("$sync_time_s"));
  5942.     return params;
  5943. }
  5944.  
  5945.  
  5946. //!!! Would be better to store in a command buffer.
  5947. function su_sync_done(res)
  5948. {
  5949.     var context = res.detail;
  5950.     
  5951. //    if (context.stopped)
  5952. //        return;
  5953.     
  5954.     try {
  5955.         if (res.status != 200)
  5956.             return;
  5957.     } catch (e) { return; } 
  5958.     
  5959.     var s = "";
  5960.     if (typeof(res.responseText) != "undefined")
  5961.         s = res.responseText;
  5962.     
  5963.     if (su_log_communication)
  5964.         su_log("response sync.php", s);
  5965.     
  5966.     su_process_commands(s, context, true, 10); 
  5967. }
  5968.  
  5969. function su_process_commands(str, opt_context, opt_async, opt_async_interval)
  5970. {
  5971.     var commands = str.split("\n");
  5972.     var i;
  5973.     var interval;
  5974.     var context = (opt_context) ?  opt_context : new Object();
  5975.     
  5976.     if (opt_async)
  5977.     {
  5978.         context.async_commands = commands;
  5979.         context.async_interval = (opt_async_interval) ? opt_async_interval : 0;
  5980.         setTimeout(su_process_commands2, 0, context);
  5981.     }        
  5982.     else
  5983.     {
  5984.         for (i = 0; i < commands.length; i++)
  5985.         {
  5986.             if (commands[i] == "")
  5987.                 continue;
  5988.             su_process_command(commands[i], context);
  5989.         }
  5990.         setTimeout(function () { su_ds.flushPrefs(); }, 100);
  5991.     }
  5992. }
  5993.  
  5994. function su_process_commands2(context)
  5995. {
  5996.     var command = context.async_commands.shift();
  5997.     
  5998.     if (command != "")
  5999.         su_process_command(command, context);
  6000.     
  6001.     if (context.async_commands.length)
  6002.     {
  6003.         setTimeout(su_process_commands2, context.async_interval, context);
  6004.     }
  6005.     else
  6006.     {
  6007.         su_ds.flushPrefs();
  6008.         su_refresh_pagemeta(false, 10);
  6009.     }
  6010. }
  6011.  
  6012. function su_process_command(command_str, context, opt_command_parts)
  6013. {
  6014.     try {
  6015.     
  6016.     var val;
  6017.     var el;
  6018.     var detail;
  6019.     
  6020.     var command_parts;
  6021.     if (opt_command_parts)
  6022.         command_parts = opt_command_parts;
  6023.     else
  6024.         command_parts = command_str.split(" ");
  6025.     
  6026.     switch (command_parts[0])
  6027.     {
  6028.         case "SYNC":
  6029.             if (stumbleid == 0)
  6030.                 break;
  6031.             if (su_disable_sync)
  6032.                 return;
  6033.             if (command_parts.length >= 2)
  6034.                 su_ds.setValue("$sync_time_s", parseInt(command_parts[1]));
  6035.             if (command_parts.length >= 3)
  6036.                 su_ds.setValue("$sync_retry", parseInt(command_parts[2]));
  6037.             if (command_parts.length >= 4)
  6038.             {
  6039.                 var retry_interval_s = parseInt(command_parts[3]);
  6040.                 var retry_time_s = su_get_time_s() + retry_interval_s;
  6041.                 su_ds.setValue("$sync_retry_time_s", retry_time_s);
  6042.                 setTimeout(su_sync, retry_interval_s * 1000);
  6043.             }
  6044.             break;
  6045.         case "NICK":
  6046.             if (stumbleid == 0)
  6047.                 break;
  6048.             if (su_prev_nick != command_parts[1])
  6049.             {
  6050.                 su_prev_nick = command_parts[1];
  6051.                 su_ds.setValue("$nick", command_parts[1]);
  6052.             }
  6053.             break;
  6054.         case "MESSAGE":
  6055.             if (stumbleid == 0)
  6056.                 break;
  6057.             su_set_inbox_status('2');
  6058.             su_register_activity("message-notify");
  6059.             break;
  6060.         case "FRIENDS":
  6061.             setTimeout(su_process_friends_command, 0, command_str);
  6062.             break;
  6063.         case "SEENCONF":
  6064.             su_process_seenconf_command(command_parts[1], context);
  6065.             break;
  6066.         case "DONE":
  6067.             context.done = true;
  6068.             break;
  6069.         case "KEY":
  6070.             if (context.mode == 1)
  6071.             {
  6072.                 context.prekey = command_parts[1];
  6073.             }
  6074.             else if (context.mode == 2)
  6075.             {
  6076.                 context.prekey = command_parts[1];
  6077.                 context.prekey2 = command_parts[2];
  6078.             }
  6079.             break;
  6080.         case "SQCS":
  6081.             if (stumbleid == 0)
  6082.                 break;
  6083.             if (su_ds.getValue("$undelivered_count") == 0)
  6084.                 clear_stumbles();
  6085.             break;
  6086.         case "SQCF":
  6087.             if (stumbleid == 0)
  6088.                 break;
  6089.             clear_stumbles();
  6090.             break;
  6091.         case "META":
  6092.             try {
  6093.                 su_process_meta_command(command_parts, context);
  6094.                 if (su_log_sync)
  6095.                     su_logf(command_str);
  6096.             } catch (e) { su_log_error("META COMMAND", e); }
  6097.             break;
  6098.         case "MEDR":
  6099.             try {
  6100.                 su_process_medr_command(command_parts, context);
  6101.                 if (su_log_sync)
  6102.                     su_logf(command_str);
  6103.             } catch (e) { su_log_error("MEDR COMMAND", e); }
  6104.             break;
  6105.         case "MEDT":
  6106.             try {
  6107.                 su_process_medt_command(command_parts, context);
  6108.                 if (su_log_sync)
  6109.                     su_logf(command_str);
  6110.             } catch (e) { su_log_error("MEDT COMMAND", e); }
  6111.             break;
  6112.         case "BKDA":
  6113.             try {
  6114.                 su_process_bkda_command(command_parts, context);
  6115.                 if (su_log_sync)
  6116.                     su_logf(command_str);
  6117.             } catch (e) { su_log_error("BKDA COMMAND", e); }
  6118.             break;
  6119.         case "BKDR":
  6120.             try {
  6121.                 su_process_bkdr_command(command_parts, context);
  6122.                 if (su_log_sync)
  6123.                     su_logf(command_str);
  6124.             } catch (e) { su_log_error("BKDR COMMAND", e); }
  6125.             break;
  6126.         case "BKDC":
  6127.             try {
  6128.                 su_process_bkdc_command();
  6129.                 if (su_log_sync)
  6130.                     su_logf(command_str);
  6131.             } catch (e) { su_log_error("BKDC COMMAND", e); }
  6132.             break;
  6133.         case "TOPICS":
  6134.             try {
  6135.                 su_process_topics_command(command_parts);
  6136.             } catch (e) { su_log_error("TOPICS COMMAND", e); }
  6137.             break;
  6138.         case "UPDATETOPICS":
  6139.             try {
  6140.                 su_update_topics_command(command_parts);
  6141.             } catch(e) { su_log_error("UPDATETOPICS COMMAND", e); }
  6142.             break;
  6143.         case "OK":
  6144.             if (stumbleid == 0)
  6145.                 break;
  6146.             if (command_parts.length >= 2)
  6147.                 su_ds.setCC(command_parts[1]);
  6148.             break;
  6149.         case "SACK":
  6150.             if (stumbleid == 0)
  6151.                 break;
  6152.             context.sack = true;
  6153.             if (command_parts.length >= 2)
  6154.                 su_ds.setValue("$sync_time_s", command_parts[1]);
  6155.             if (command_parts.length >= 3)
  6156.                 su_ds.setValue("$sync_cur_q", command_parts[2]);
  6157.             if (command_parts.length >= 4)
  6158.                 su_ds.setValue("$sync_cur_t", command_parts[3]);
  6159.             if (command_parts.length >= 5)
  6160.                 su_ds.setValue("$sync_cur_s", command_parts[4]);
  6161.             if (command_parts.length >= 6)
  6162.                 su_ds.setValue("$sync_pre_q", command_parts[5]);
  6163.             if (command_parts.length >= 7)
  6164.                 su_ds.setValue("$sync_pre_t", command_parts[6]);
  6165.             if (command_parts.length >= 8)
  6166.                 su_ds.setValue("$sync_pre_s", command_parts[7]);
  6167.             break;
  6168.         case "ENABLEG":
  6169.             su_enable_client_features(parseInt(command_parts[1]));
  6170.             break;
  6171.         case "DISABLEG":
  6172.             su_disable_client_features(parseInt(command_parts[1]));
  6173.             break;
  6174.         case "ENABLEU":
  6175.             su_enable_user_features(parseInt(command_parts[1]));
  6176.             break;
  6177.         case "DISABLEU":
  6178.             su_disable_user_features(parseInt(command_parts[1]));
  6179.             break;
  6180.         case "ALLAVATARS":
  6181.             if (stumbleid == 0)
  6182.                 break;
  6183.             su_ds.setValue("$has_avatars", false);
  6184.             break;
  6185.         case "TAGGER":
  6186.             if (stumbleid == 0)
  6187.                 break;
  6188.             su_enable_user_features(0x2);
  6189.             break;
  6190.         case "FACEBOOK":
  6191.             if (stumbleid == 0)
  6192.                 break;
  6193.             switch (command_parts[1])
  6194.             {
  6195.                 case "1":
  6196.                     su_ds.setValue("$facebook_added", true);
  6197.                     su_ds.setValue("$facebook_linked", false);
  6198.                     break;
  6199.                 case "2":
  6200.                     su_ds.setValue("$facebook_added", true);
  6201.                     su_ds.setValue("$facebook_linked", true);
  6202.                     break;
  6203.             }
  6204.             break;
  6205.         case "UPGRADE":
  6206.             if (stumbleid == 0)
  6207.                 break;
  6208.             su_set_visible("su_upgrade", true);
  6209.             break;
  6210.         case "FIRSTFRIEND": 
  6211.             if (stumbleid == 0)
  6212.                 break;
  6213.             su_ds.setValue("$firstfriends", command_str);
  6214.             break;
  6215. //        case "SPONSOR":
  6216. //            su_ds.setValue("$sponsor", true);
  6217. //            break;
  6218. //        case "NOSPONSOR":
  6219. //            su_ds.setValue("$sponsor", false);
  6220. //            break;
  6221.         case "REGID":
  6222.             su_ds.setValue("@dist_regid", command_parts[1]);
  6223.             break;
  6224.         case "SETU":
  6225.             if (stumbleid == 0)
  6226.                 break;
  6227.             su_process_set_pref_command("$" + command_parts[1], command_parts[2]);
  6228.             break;
  6229.         case "SETG":
  6230.             su_process_set_pref_command("@" + command_parts[1], command_parts[2]);
  6231.             break;
  6232.         case "STUMBLENOW":
  6233.             su_process_stumble_now_command(command_str);
  6234.             break;
  6235.         case "SUPR_TWITTER_LINK":
  6236.             if(stumbleid == 0)
  6237.                 break;
  6238.             su_ds.setValue("$twitter_supr_linked", (command_parts[1] == "1") ? true : false);
  6239.             su_refresh_referral_menu(10);
  6240.             break;
  6241.         case "SUPR_FACEBOOK_LINK":
  6242.             if(stumbleid == 0)
  6243.                 break;
  6244.             su_ds.setValue("$facebook_supr_linked", (command_parts[1] == "1") ? true : false);
  6245.             su_refresh_referral_menu(11);
  6246.             break;
  6247.         case "SFC":
  6248.             su_process_sync_favorites_count_command(parseInt(command_parts[1]));
  6249.             break;
  6250.         case "SSC":
  6251.             su_process_sync_stumble_count_command(parseInt(command_parts[1]));
  6252.             break;
  6253.         case "SHOWURL":
  6254.             if(context.share)
  6255.             {
  6256.                 su_process_showurl_command(command_parts, context);
  6257.             }
  6258.             break;
  6259.         case "ERROR":
  6260.             su_process_error_command(command_parts, context);
  6261.             break;
  6262.     }
  6263.     
  6264.     } catch (e) { su_log_error("PROCESS " + command_parts[0], e, command_str); }  
  6265. }
  6266.  
  6267. function su_get_browser_centered_window_pos(width, height)
  6268. {
  6269.     var topWin = window.top;
  6270.     var pos = {};
  6271.     pos.left = (topWin.outerWidth - width) / 2 + topWin.screenX;
  6272.     pos.top = (topWin.outerHeight - height) / 2 + topWin.screenY;
  6273.     
  6274.     return pos;
  6275. }
  6276.  
  6277. function su_process_showurl_command(command_parts, context)
  6278. {
  6279.     var targetUrl = command_parts[1];
  6280.     var width = parseInt(command_parts[2]);
  6281.     var height = parseInt(command_parts[3]);
  6282.     var options = "dialog=1,toolbar=0,status=0,resizable=1,scrollbars=1";
  6283.     if((command_parts.length > 4) && (command_parts[4] != ''))
  6284.     {
  6285.         options = command_parts[4];
  6286.     }
  6287.     var name = "_blank";
  6288.     if(context.target)
  6289.         name = "su_" + context.target;
  6290.     
  6291.     var pos = su_get_browser_centered_window_pos(width, height);
  6292.     options += ',left=' + pos.left;
  6293.     options += ',top=' + pos.top;
  6294.     options += ',width=' + width;
  6295.     options += ',height=' + height;
  6296.     
  6297.     window.open(targetUrl, name, options);
  6298.  
  6299. }
  6300.  
  6301. function su_process_stumble_now_command(command_str)
  6302. {
  6303.     var parts = command_str.split(" ");
  6304.     
  6305.     if (parts.length < 2)
  6306.         return;
  6307.     
  6308.     // Treat it just like we treat the through.php command
  6309.     var args = parts[1].split("&");
  6310.     su_process_stumble_now(args);
  6311. }
  6312.  
  6313. function su_process_sync_favorites_count_command(count)
  6314. {
  6315.     if(su_ds.getValue("@enable_server_counts") && (count != su_ds.getValue("$thumbup_count")))
  6316.     {
  6317.         su_ds.setValue("$thumbup_count", count);
  6318.         su_thumbup_count_changed();
  6319.     }
  6320. }
  6321.  
  6322. function su_process_sync_stumble_count_command(count)
  6323. {
  6324.     if(su_ds.getValue("@enable_server_counts") && (count != su_ds.getValue("$stumble_count")))
  6325.     {
  6326.         su_ds.setValue("$stumble_count", count);
  6327.         su_stumble_count_changed();
  6328.     }
  6329. }
  6330.  
  6331. function su_thumbup_count_changed()
  6332. {
  6333.     var count = su_ds.getValue("$thumbup_count");
  6334.     if( (count >= 1) && !su_ds.getValue("$show_info") && !su_ds.getValue("$show_info_user_changed") )
  6335.     {
  6336.         // Show the info button after the first thumbup.
  6337.         su_ds.setValue("$show_info", true);
  6338.         su_set_visible("su_website_info", true);
  6339.     }
  6340.     
  6341.     if( (count >= 3) && !su_ds.getValue("$show_home") && !su_ds.getValue("$show_home_user_changed") )
  6342.     {
  6343.         // Show the favorites button after the third thumbup.
  6344.         su_ds.setValue("$show_home", true);
  6345.         su_set_visible("su_profile", true);
  6346.     }
  6347. }
  6348.  
  6349. function su_stumble_count_changed()
  6350. {
  6351.     var count = su_ds.getValue("$stumble_count");
  6352.     if( (count > 99) && !su_ds.getValue("$show_friends") && !su_ds.getValue("$show_friends_user_changed") )
  6353.     {
  6354.         // After 100 stumbles, show the "Stumblers" button.
  6355.         su_ds.setValue("$show_friends", true);
  6356.         su_set_visible("su_friends", true);
  6357.     }
  6358. }
  6359.  
  6360. function su_process_seenconf_command(ids, context)
  6361. {
  6362.     if(context && context.oldStumbleReport)
  6363.     {
  6364.         su_process_old_seenconf_command(ids);
  6365.         return;
  6366.     }
  6367.     
  6368.     // It's not an old format stumble request so we expect this to just be a single
  6369.     // publicid.
  6370.     context.confirmed = ids;
  6371. }
  6372.  
  6373. function su_process_old_seenconf_command(conf_urlids_str)
  6374. {
  6375.     var conf_urlids;
  6376.     var seen_urlids;
  6377.     var stumbletimes;
  6378.     var stumbletypes;
  6379.     var stumblereferrals;
  6380.     var str;
  6381.     var i;
  6382.     var j;
  6383.     
  6384.     if (conf_urlids_str == "")
  6385.         return;
  6386.     
  6387.     if (su_ds.getValue("$stumblestats") == conf_urlids_str ||
  6388.             conf_urlids_str == "[clear]")
  6389.     {
  6390.         seen_urlids = [];
  6391.         stumbletimes = [];
  6392.         stumbletypes = [];
  6393.         stumblereferrals = [];
  6394.     }
  6395.     else
  6396.     {
  6397.         str = su_ds.getValue("$stumblestats");
  6398.         seen_urlids = str.split(".");
  6399.         str = su_ds.getValue("$stumbletimes");
  6400.         stumbletimes = str.split(".");
  6401.         str = su_ds.getValue("$stumbletypes");
  6402.         stumbletypes = str.split(".");
  6403.         str = su_ds.getValue("$stumblereferrals");
  6404.         stumblereferrals = str.split(".");
  6405.         
  6406.         conf_urlids = conf_urlids_str.split(".");
  6407.         
  6408.         for (i = 0; i < conf_urlids.length; i++)
  6409.         {
  6410.             for (j = 0; j < seen_urlids.length; j++)
  6411.             {
  6412.                 if (conf_urlids[i] == seen_urlids[j])
  6413.                 {
  6414.                     seen_urlids.splice(j, 1);
  6415.                     stumbletimes.splice(j, 1);
  6416.                     stumbletypes.splice(j, 1);
  6417.                     stumblereferrals.splice(j, 1);
  6418.                     break;
  6419.                 }
  6420.             }
  6421.         }
  6422.     }
  6423.  
  6424.     su_ds.setValue("$stumblestats", seen_urlids.join("."));
  6425.     su_ds.setValue("$stumbletimes", stumbletimes.join("."));
  6426.     su_ds.setValue("$stumbletypes", stumbletypes.join("."));
  6427.     su_ds.setValue("$stumblereferrals", stumblereferrals.join("."));
  6428.     su_ds.setValue("$last_uploaded", (new Date()).getTime());
  6429.     su_ds.flushPrefs();
  6430. }
  6431.  
  6432. function su_enqueue_command(priority, command)
  6433. {
  6434.     if (! su_host.places)
  6435.         return;
  6436.     
  6437.     var db = su_ds.getDatabase();
  6438.     db.a("INSERT INTO command_queue (priority, command) VALUES (");
  6439.     db.av(priority);
  6440.     db.als(command);
  6441.     db.query();
  6442. }
  6443.  
  6444. function su_count_enqueued_commands(priority)
  6445. {
  6446.     if (! su_host.places)
  6447.         return;
  6448.     
  6449.     var db = su_ds.getDatabase();
  6450.     var sql = "SELECT count(*) as count FROM command_queue WHERE priority=" + db.v(priority);
  6451.     var result = db.query(sql);
  6452.     var row;
  6453.     if (row = result.shift())
  6454.         return row.count;
  6455.     else
  6456.         return 0;
  6457. }
  6458.  
  6459. function su_process_topics_command(parts)
  6460. {
  6461.     if (parts.length < 2)
  6462.         return;
  6463.     
  6464.     parts.shift();
  6465.     
  6466.     su_process_topic_list(parts.join(" "));
  6467. }
  6468.  
  6469. function su_update_topics_command(parts)
  6470. {
  6471.     if (parts.length < 2)
  6472.         return;
  6473.     
  6474.     parts.shift();
  6475.     
  6476.     su_update_topic_list(parts.join(" "));
  6477. }
  6478.  
  6479. function su_process_error_command(parts, context)
  6480. {
  6481.     if (! context)
  6482.     {
  6483.         su_log("warning: missing context for error");
  6484.         return;
  6485.     }
  6486.     
  6487.     context.error = true;
  6488.     
  6489.     if (context.quiet)
  6490.         return;
  6491.     
  6492.     su_handle_error(parts[1]);
  6493. }
  6494.  
  6495. function su_process_bkda_command(parts, context)
  6496. {
  6497.     if (! su_host.places)
  6498.         return;
  6499.     
  6500.     if (parts.length < 3)
  6501.         return;
  6502.     
  6503.     var spec = new Object();
  6504.     spec.domain = parts[1];
  6505.     spec.timestamp = parseInt(parts[2]);
  6506.  
  6507.     var db = su_ds.getDatabase();
  6508.     var row;
  6509.     var result;
  6510.     var sql;
  6511.     
  6512.     if (context.from_sync)
  6513.     {
  6514.         sql = "SELECT modified FROM blocked_domain WHERE domain=" + db.q(spec.domain);
  6515.         result = db.query(sql);
  6516.         if (row = result.shift())
  6517.         {
  6518.             // Ignore obsolete sync commands
  6519.             var offset = spec.timestamp - row.modified;
  6520.             if (offset < (- su_ds.getValue("@server_time_float_s")))
  6521.                 return;
  6522.         }
  6523.     }
  6524.     
  6525.     db.a("INSERT INTO blocked_domain (domain, modified, active) VALUES (");
  6526.     db.as(spec.domain);
  6527.     db.av(spec.timestamp);
  6528.     db.alv(1);
  6529.     db.query();
  6530. }
  6531.  
  6532. function su_process_bkdr_command(parts, context)
  6533. {
  6534.     if (! su_host.places)
  6535.         return;
  6536.     
  6537.     if (parts.length < 3)
  6538.         return;
  6539.     
  6540.     var spec = new Object();
  6541.     spec.domain = parts[1];
  6542.     spec.timestamp = parseInt(parts[2]);
  6543.     
  6544.     var db = su_ds.getDatabase();
  6545.     var row;
  6546.     var result;
  6547.     var sql;
  6548.     
  6549.     if (context.from_sync)
  6550.     {
  6551.         sql = "SELECT modified FROM blocked_domain WHERE domain=" + db.q(spec.domain);
  6552.         result = db.query(sql);
  6553.         if (row = result.shift())
  6554.         {
  6555.             // Ignore obsolete sync commands
  6556.             var offset = spec.timestamp - row.modified;
  6557.             if (offset < (- su_ds.getValue("@server_time_float_s")))
  6558.                 return;
  6559.         }
  6560.     }
  6561.     
  6562.     db.a("INSERT INTO blocked_domain (domain, modified, active) VALUES (");
  6563.     db.as(spec.domain);
  6564.     db.av(spec.timestamp);
  6565.     db.alv(0);
  6566.     db.query();
  6567. }
  6568.  
  6569. function su_process_bkdc_command()
  6570. {
  6571.     if (! su_host.places)
  6572.         return;
  6573.     
  6574.     var db = su_ds.getDatabase();
  6575.     var sql;
  6576.     
  6577.     sql = "UPDATE blocked_domain SET active=0";
  6578.     db.query(sql);
  6579. }
  6580.  
  6581. function su_process_medt_command(parts, context)
  6582. {
  6583.     if (! su_host.places)
  6584.         return;
  6585.     
  6586.     var field_names = new Array(
  6587.         "urlid",                  //  1
  6588.         "tagid",                  //  2
  6589.         "timestamp");             //  3
  6590.  
  6591.     parts.shift();
  6592.     
  6593.     var spec = new Object();
  6594.     var i;
  6595.     for (i = 0; i < field_names.length; i++)
  6596.     {
  6597.         if (parts.length > 0)
  6598.             spec[field_names[i]] = parts.shift();
  6599.         else
  6600.             spec[field_names[i]] = null;
  6601.         
  6602.         if (spec[field_names[i]] == "")
  6603.             spec[field_names[i]] = null;
  6604.     }
  6605.     
  6606.     spec.tagid = parseInt(spec.tagid);
  6607.     
  6608.     var result;
  6609.     var row;
  6610.     var result2;
  6611.     var row2;
  6612.     var id;
  6613.     var ids;
  6614.     var nsiuri;
  6615.     var tags = new Array();
  6616.     var db = su_ds.getDatabase();
  6617.     var sql;
  6618.     
  6619.     if (context.from_sync)
  6620.     {
  6621.         sql = "SELECT tag_applied FROM url_tag WHERE urlid=" + db.q(spec.urlid) + " AND tagid=" + db.v(spec.tagid);
  6622.         result = db.query(sql);
  6623.         if (row = result.shift())
  6624.         {
  6625.             // Ignore obsolete sync commands
  6626.             var offset = spec.timestamp - row.tag_applied;
  6627.             if (offset < (- su_ds.getValue("@server_time_float_s")))
  6628.                 return;
  6629.         }
  6630.     }
  6631.     
  6632.     // if this tag has been applied to another url, keep the tag record
  6633.     sql = "SELECT urlid FROM url_tag WHERE tagid=" + db.v(spec.tagid) + " AND urlid!=" + db.q(spec.urlid) + " LIMIT 1";
  6634.     result = db.query(sql);
  6635.     var keep_tag = false;
  6636.     if (result.length)
  6637.         keep_tag = true;
  6638.     
  6639.     // if this url has been rated, keep the url record  
  6640.     sql = "SELECT rating FROM url WHERE urlid=" + db.q(spec.urlid) + " AND rating!=-1";
  6641.     result = db.query(sql);
  6642.     var keep_url = false;
  6643.     if (result.length)
  6644.         keep_url = true;
  6645.     
  6646.     if (! keep_url)
  6647.     {
  6648.         // if this url has a non-autotag other than the tag to be nuked, keep the url record  
  6649.         sql = "SELECT tagid FROM url_tag WHERE urlid=" + db.q(spec.urlid) + " AND tagid!=" + db.v(spec.tagid) + " AND tagid>1000 AND tagid!=" + db.v(su_video_tagid) + " LIMIT 1";
  6650.         result = db.query(sql);
  6651.         if (result.length)
  6652.             keep_url = true;
  6653.     }
  6654.     
  6655.     if (su_ds.getValue("$sync_bm_meta"))
  6656.     {
  6657.         var ts = su_ds.getTaggingService();
  6658.         
  6659.         if (keep_url)
  6660.         {
  6661.             sql = "SELECT tag FROM tag_map WHERE tagid=" + db.v(spec.tagid);
  6662.             result = db.query(sql);
  6663.             while (row = result.shift())
  6664.                 tags.push(row.tag);
  6665.         }
  6666.         else
  6667.         {
  6668.             sql = "SELECT tag FROM url_tag NATURAL JOIN tag_map WHERE url_tag.urlid=" + db.q(spec.urlid);
  6669.             result = db.query(sql);
  6670.             while (row = result.shift())
  6671.                 tags.push(row.tag);
  6672.             tags.push("SU"); // for good measure
  6673.             
  6674.             sql = "SELECT catid FROM url WHERE urlid=" + db.q(spec.urlid);
  6675.             result = db.query(sql);
  6676.             if (row = result.shift())
  6677.             {
  6678.                 if (su_ds.getBMTagFromCatid(row.catid))
  6679.                     tags.push(su_ds.getBMTagFromCatid(row.catid));
  6680.             }
  6681.         }
  6682.         
  6683.         if (tags.length)
  6684.         {
  6685.             sql = "SELECT url FROM url_tag NATURAL JOIN url_map WHERE url_tag.urlid=" + db.q(spec.urlid) + " AND url_tag.tagid=" + db.v(spec.tagid);
  6686.             result = db.query(sql);
  6687.             for (j = 0; row = result[j]; j++)
  6688.             {
  6689.                 nsiuri = su_get_nsiuri(row.url);
  6690.                 
  6691.                 ts.untagURI(nsiuri, tags);
  6692.                 
  6693.                 if (! keep_url)
  6694.                     su_remove_managed_bookmark(nsiuri);
  6695.             }
  6696.         }
  6697.     }
  6698.     
  6699.     if (! keep_url)
  6700.     {
  6701.         sql = "DELETE FROM url_map WHERE urlid=" + db.q(spec.urlid);
  6702.         db.query(sql);
  6703.         sql = "DELETE FROM url WHERE urlid=" + db.q(spec.urlid);
  6704.         db.query(sql);
  6705.     }
  6706.     
  6707.     if (! keep_tag)
  6708.     {
  6709.         sql = "DELETE FROM tag_map WHERE tagid=" + db.v(spec.tagid);
  6710.         db.query(sql);
  6711.     }
  6712.     
  6713.     sql = "DELETE FROM url_tag WHERE urlid=" + db.q(spec.urlid) + " AND tagid=" + db.v(spec.tagid);
  6714.     db.query(sql);
  6715. }
  6716.  
  6717. function su_process_medr_command(parts, context)
  6718. {
  6719.     if (! su_host.places)
  6720.         return;
  6721.  
  6722.     var field_names = new Array(
  6723.         "urlid",                  //  1
  6724.         "timestamp");             //  2
  6725.  
  6726.     parts.shift();
  6727.     
  6728.     var spec = new Object();
  6729.     var i;
  6730.     var j;
  6731.     for (i = 0; i < field_names.length; i++)
  6732.     {
  6733.         if (parts.length > 0)
  6734.             spec[field_names[i]] = parts.shift();
  6735.         else
  6736.             spec[field_names[i]] = null;
  6737.         
  6738.         if (spec[field_names[i]] == "")
  6739.             spec[field_names[i]] = null;
  6740.     }
  6741.     
  6742.     var result;
  6743.     var row;
  6744.     var db = su_ds.getDatabase();
  6745.     var sql;
  6746.     
  6747.     if (context.from_sync)
  6748.     {
  6749.         sql = "SELECT rating_applied FROM url WHERE urlid=" + db.q(spec.urlid);
  6750.         result = db.query(sql);
  6751.         if (row = result.shift())
  6752.         {
  6753.             // Ignore obsolete sync commands
  6754.             var offset = spec.timestamp - row.rating_applied;
  6755.             if (offset < (- su_ds.getValue("@server_time_float_s")))
  6756.                 return;
  6757.         }
  6758.     }
  6759.     
  6760.     if (context.ref_url)
  6761.         su_delete_rating(context.ref_url);
  6762.     
  6763.     var usertags = su_get_db_tags(spec.urlid, false, true, true);
  6764.     
  6765.     if (su_ds.getValue("$sync_bm_meta"))
  6766.         su_remove_thumbup_bookmark(spec.urlid, null, usertags);
  6767.     
  6768.     if (usertags)
  6769.     {
  6770.         sql = "UPDATE url SET rating=-1 WHERE urlid=" + db.q(spec.urlid);
  6771.         db.query(sql);
  6772.     }
  6773.     else
  6774.     {
  6775.         sql = "DELETE FROM url WHERE urlid=" + db.q(spec.urlid);
  6776.         db.query(sql);
  6777.         sql = "DELETE FROM url_map WHERE urlid=" + db.q(spec.urlid);
  6778.         db.query(sql);
  6779.     }
  6780. }
  6781.  
  6782. function su_process_meta_command(parts, context)
  6783. {
  6784.     if (! su_host.places)
  6785.         return;
  6786.     
  6787. //    if ((context.mode == 1) || (context.mode == 2))
  6788. //        context.count++;
  6789.     
  6790.     var field_names = new Array(
  6791.         "urlid",                  //  1
  6792.         "ref_url",                //  2
  6793.         "title",                  //  3
  6794.         "catid",                  //  4
  6795.         "comment_level",          //  5
  6796.         "score",                  //  6
  6797.         "rating",                 //  7
  6798.         "rating_applied",         //  8
  6799.         "tagid",                  //  9
  6800.         "tag",                    // 10
  6801.         "tag_applied");           // 11
  6802.     
  6803.     parts.shift();
  6804.     
  6805.     var spec = new Object();
  6806.     var i;
  6807.     for (i = 0; i < field_names.length; i++)
  6808.     {
  6809.         if (parts.length > 0)
  6810.             spec[field_names[i]] = parts.shift();
  6811.         else
  6812.             spec[field_names[i]] = null;
  6813.         
  6814.         if (spec[field_names[i]] == "")
  6815.             spec[field_names[i]] = null;
  6816.     }
  6817.     
  6818.     if (context.ref_url)
  6819.         spec.ref_url = context.ref_url;
  6820.     
  6821.     if (context.title)
  6822.     {
  6823.         spec.title = context.title;
  6824.     }
  6825.     else if (spec.title)
  6826.     {
  6827.         try {
  6828.             spec.title = decodeURIComponent(spec.title);
  6829.         } catch (e) { su_log_error("DECODE TITLE", e); }
  6830.     }
  6831.     
  6832.     if (! spec.title)
  6833.         spec.title = spec.ref_url;
  6834.     
  6835.     if (! spec.title)
  6836.     {
  6837.         su_log("missing title");
  6838.         return;
  6839.     }
  6840.     
  6841.     var db = su_ds.getDatabase();
  6842.     var sql;
  6843.     var result;
  6844.     var row;
  6845.     var tags = new Array();
  6846.     var old_catid = null;
  6847.     
  6848.     sql = "SELECT catid FROM url WHERE urlid=" + db.q(spec.urlid);
  6849.     result = db.query(sql);
  6850.     
  6851.     if (row = result.shift())
  6852.         old_catid = row.catid;
  6853.     
  6854.     var local_catid = su_ds.lookup("url:local_catid", spec.ref_url);
  6855.     
  6856.     if (local_catid)
  6857.         spec.catid = local_catid;
  6858.     else if (spec.catid)
  6859.         spec.catid = parseInt(spec.catid);
  6860.     else if (old_catid)
  6861.         spec.catid = old_catid;
  6862.     else
  6863.         spec.catid = 0;
  6864.  
  6865.     if ((typeof context.rating) != "undefined")
  6866.         spec.rating = context.rating;
  6867.     
  6868.     var tag;
  6869.     if (spec.tag)
  6870.     {
  6871.         spec.tagid = parseInt(spec.tagid);
  6872.         spec.tag_applied = parseInt(spec.tag_applied);
  6873.         if (! spec.tagid)
  6874.         {
  6875.             su_log("missing tagid");
  6876.             return;
  6877.         }
  6878.         
  6879.         if (! spec.tag_applied)
  6880.         {
  6881.             su_log("missing tag_applied");
  6882.             return;
  6883.         }
  6884.         
  6885.         if (spec.tagid == su_video_tagid)
  6886.             tag = "video";
  6887.         else if (context.ref_tag)
  6888.             tag = su_ds.getBMTagFromTag(context.ref_tag);
  6889.         else if (spec.tagid < 1000)
  6890.             tag = su_ds.getBMTagFromCatid(spec.tagid);
  6891.         else
  6892.             tag = su_ds.getBMTagFromTag(spec.tag);
  6893.         
  6894.         if (tag)
  6895.             tags.push(tag);
  6896.         
  6897.         sql = "SELECT rating,rating_applied FROM url WHERE urlid=" + db.q(spec.urlid);
  6898.         result = db.query(sql);
  6899.         if (row = result.shift())
  6900.         {
  6901.             spec.rating = row.rating;
  6902.             spec.rating_applied = row.rating_applied;
  6903.             if ((spec.rating == 1) && (spec.tagid == su_video_tagid))
  6904.                 context.has_video_favs = true;
  6905.         }
  6906.         else
  6907.         {
  6908.             spec.rating = -1;
  6909.             spec.rating_applied = 0;
  6910.         }
  6911.         
  6912.     }
  6913.     
  6914.     if (spec.rating == null)
  6915.     {
  6916.         sql = "SELECT rating FROM url WHERE urlid=" + db.q(spec.urlid);
  6917.         result = db.query(sql);
  6918.         if (row = result.shift())
  6919.             spec.rating = row.rating;
  6920.         else
  6921.             spec.rating = -1;
  6922.     }
  6923.     else
  6924.     {
  6925.         spec.rating = parseInt(spec.rating);
  6926.     }
  6927.     
  6928.     if ((spec.rating == -1) && (! spec.tagid))
  6929.         return; // equivalent to medr plus autotag info
  6930.     
  6931.     var bms = su_ds.getBookmarksService();
  6932.     var timestamp_us;
  6933.     var itemid;
  6934.     var i;
  6935.     var ts;
  6936.     var nsiuri;
  6937.     var urls;
  6938.     var url;
  6939.     var folderid;    
  6940.  
  6941. /*    
  6942.     if ((context.mode == 1) || (context.mode == 2))
  6943.     {
  6944.         // Mode 1 is the favs batch download
  6945.         // Mode 2 is the custom tags batch download
  6946.         
  6947.         nsiuri = su_get_nsiuri(spec.ref_url);
  6948.     
  6949.         // Only create a bookmark if they don't have this url bookmarked
  6950.         // already.  If they already have it somewhere, we'll just apply
  6951.         // tags.
  6952.         
  6953.         if (! su_is_bookmarked(nsiuri))
  6954.         {
  6955.             //!!! Checking folderid every time is a bit expensive but
  6956.             //    probably necessary since we allow interaction during
  6957.             //    download.
  6958.             
  6959.             folderid = su_get_supertopic_folderid(spec.catid, true);
  6960.             
  6961.             if (folderid)
  6962.             {
  6963.                 itemid = bms.insertBookmark(
  6964.                         folderid,
  6965.                         nsiuri,
  6966.                         bms.DEFAULT_INDEX,
  6967.                         spec.title);
  6968.         
  6969.                 timestamp_us = spec.rating_applied * 1000000;
  6970.                 bms.setItemDateAdded(itemid, timestamp_us);
  6971.                 bms.setItemLastModified(itemid, timestamp_us);
  6972.             }
  6973.         }
  6974.         
  6975.         
  6976.         // build the tag set
  6977.         
  6978.         var skip = (su_is_adult_category(spec.catid) && (! su_ds.getValue("$sync_bm_adult")));
  6979.         
  6980.         tag = su_ds.getBMTagFromCatid(spec.catid); 
  6981.         if (tag && (! skip))
  6982.             tags.push(tag);
  6983.         
  6984.         if ((spec.rating == 1) && (! skip))
  6985.             tags.push("SU");
  6986.         
  6987.         // apply tags
  6988.         
  6989.         if (tags.length)
  6990.         {
  6991.             ts = su_ds.getTaggingService();
  6992.             try {
  6993.                 ts.tagURI(nsiuri, tags);
  6994.             } catch (e) { su_log_error("DOWNLOAD TAG", e); }
  6995.         }
  6996.     }
  6997. */
  6998.     
  6999.     if (su_ds.getValue("$sync_bm_meta"))
  7000.     {
  7001.         if (context.from_sync)
  7002.         {
  7003.             //!!! need to handle tag.modified when from_sync
  7004.             sql = "SELECT rating,rating_applied FROM url WHERE urlid=" + db.q(spec.urlid);
  7005.             result = db.query(sql);
  7006.             if (row = result.shift())
  7007.             {
  7008.                 var offset = spec.rating_applied - row.rating_applied;
  7009.                 if (offset < (- su_ds.getValue("@server_time_float_s")))
  7010.                 {
  7011.                     if (spec.tagid)
  7012.                     {
  7013.                         spec.rating = row.rating;
  7014.                         spec.rating_applied = row.rating_applied;
  7015.                     }
  7016.                     else
  7017.                     {
  7018.                         return;
  7019.                     }
  7020.                 }
  7021.             }
  7022.         }
  7023.     }
  7024.         
  7025.     db.a("INSERT OR REPLACE INTO url (urlid,title,catid,rating,rating_applied,comment_level,score) VALUES (");
  7026.     db.as(spec.urlid);
  7027.     db.as(spec.title);
  7028.     db.av(spec.catid);
  7029.     db.av(spec.rating);
  7030.     db.av(spec.rating_applied);
  7031.     db.av(spec.comment_level);
  7032.     db.alv(spec.score);
  7033.     db.query();
  7034.     
  7035.     db.a("INSERT OR REPLACE INTO url_map (url,urlid) VALUES (");
  7036.     db.as(spec.ref_url);
  7037.     db.als(spec.urlid);
  7038.     db.query();
  7039.  
  7040.     if (spec.tagid && spec.tag && spec.tag_applied)
  7041.     {
  7042.         db.a("INSERT OR REPLACE INTO tag_map (tag,tagid) VALUES (");
  7043.         db.as(spec.tag);
  7044.         db.alv(spec.tagid);
  7045.         db.query();
  7046.         
  7047.         db.a("INSERT OR REPLACE INTO url_tag (urlid,tagid,tag_applied) VALUES (");
  7048.         db.as(spec.urlid);
  7049.         db.av(spec.tagid);
  7050.         db.alv(spec.tag_applied);
  7051.         db.query();
  7052.     }
  7053.     
  7054.     if ((context.mode == 1) || (context.mode == 2)
  7055.             || (! su_ds.getValue("$sync_bm_meta")))
  7056.         return;
  7057.     
  7058.     if (old_catid && (spec.catid != old_catid))
  7059.         su_remove_autotag(spec.urlid, old_catid);
  7060.     
  7061.     if ((spec.rating >= 1)
  7062.             && ((! su_is_adult_category(spec.catid))
  7063.             || su_ds.getValue("$sync_bm_adult")))
  7064.     {
  7065.         su_add_thumbup_bookmark(spec.urlid, spec.title, spec.catid);
  7066.     }
  7067.     else
  7068.     {
  7069.         var usertags = su_get_db_tags(spec.urlid, false, true, true);
  7070.         su_remove_thumbup_bookmark(spec.urlid, spec.title, usertags);
  7071.     }
  7072. }
  7073.  
  7074. function su_remove_autotag(urlid, catid)
  7075. {
  7076.     if (! su_host.places)
  7077.         return;
  7078.  
  7079.     var db = su_ds.getDatabase();
  7080.     var tag = su_ds.getBMTagFromCatid(catid);
  7081.     var tags = new Array();
  7082.     tags.push(tag);
  7083.     var ts = su_ds.getTaggingService();
  7084.     var row;
  7085.     var sql = "SELECT url FROM url_map WHERE urlid=" + db.q(urlid);
  7086.     var result = db.query(sql);
  7087.     while (row = result.shift())
  7088.     {
  7089.         nsiuri = su_get_nsiuri(row.url);
  7090.         ts.untagURI(nsiuri, tags);
  7091.     }
  7092. }
  7093.  
  7094. function su_change_local_catid(url, new_catid)
  7095. {
  7096.     if (! su_host.places)
  7097.         return;
  7098.     
  7099.     var urlid = su_ds.getUrlid(url);
  7100.     if (! urlid)
  7101.     {
  7102.         su_ds.define("url:local_catid", url, new_catid);
  7103.         return;
  7104.     }
  7105.     
  7106.     var db = su_ds.getDatabase();
  7107.     var row;
  7108.     var sql;
  7109.     var result;
  7110.     var old_catid;
  7111.     sql = "SELECT catid FROM url WHERE urlid=" + db.q(urlid);
  7112.     result = db.query(sql);
  7113.     if (row = result.shift())
  7114.         old_catid = row.catid;
  7115.     else
  7116.         return;
  7117.     
  7118.     if (new_catid == old_catid)
  7119.         return;
  7120.     
  7121.     sql = "UPDATE url SET catid=" + db.v(new_catid) + " WHERE urlid=" + db.q(urlid);
  7122.     db.query(sql);
  7123.     
  7124.     if (! su_ds.getValue("$sync_bm_meta"))
  7125.         return;
  7126.     
  7127.     var old_tag = su_ds.getBMTagFromCatid(old_catid);
  7128.     var old_tags = new Array();
  7129.     old_tags.push(old_tag);
  7130.     var new_tag = su_ds.getBMTagFromCatid(new_catid);
  7131.     var new_tags = new Array();
  7132.     new_tags.push(new_tag);
  7133.     var ts = su_ds.getTaggingService();
  7134.     var adult = su_is_adult_category(new_catid);
  7135.     
  7136.     sql = "SELECT url FROM url_map WHERE urlid=" + db.q(urlid);
  7137.     result = db.query(sql);
  7138.     while (row = result.shift())
  7139.     {
  7140.         nsiuri = su_get_nsiuri(row.url);
  7141.         ts.untagURI(nsiuri, old_tags);
  7142.         if ((! adult) || (adult && su_ds.getValue("$sync_bm_adult")))
  7143.             ts.tagURI(nsiuri, new_tags);
  7144.     }
  7145. }
  7146.  
  7147. function su_get_db_tags(urlid, include_autotags, include_usertags, include_adult_tags)
  7148. {
  7149.     var tags = new Array();
  7150.     var db = su_ds.getDatabase();
  7151.     var sql;
  7152.     var result;
  7153.     var row;
  7154.     
  7155.     if (include_autotags && (! include_usertags))
  7156.         sql = "SELECT tag,tag_map.tagid FROM url_tag NATURAL JOIN tag_map WHERE url_tag.urlid=" + db.q(urlid) + " AND (url_tag.tagid<1000 OR url_tag.tagid=" + db.v(su_video_tagid) + ")";
  7157.     else if ((! include_autotags) && include_usertags)
  7158.         sql = "SELECT tag,tag_map.tagid FROM url_tag NATURAL JOIN tag_map WHERE url_tag.urlid=" + db.q(urlid) + " AND url_tag.tagid>=1000 AND url_tag.tagid!=" + db.v(su_video_tagid);
  7159.     else
  7160.         sql = "SELECT tag,tag_map.tagid FROM url_tag NATURAL JOIN tag_map WHERE url_tag.urlid=" + db.q(urlid);
  7161.     
  7162.     
  7163.     result = db.query(sql);
  7164.     while (row = result.shift())
  7165.     {
  7166.         if ((! include_adult_tags) && su_is_adult_category(row.tagid))
  7167.             continue;
  7168.         
  7169.         tags.push(su_ds.getBMTagFromTag(row.tag));
  7170.     }
  7171.     
  7172.     if (include_autotags)
  7173.     {
  7174.         tags.push("SU");
  7175.         sql = "SELECT catid FROM url WHERE urlid=" + db.q(urlid);
  7176.         result = db.query(sql);
  7177.         if (row = result.shift())
  7178.         {
  7179.             if ((include_adult_tags || (! su_is_adult_category(row.catid)))
  7180.                     && su_ds.getBMTagFromCatid(row.catid))
  7181.                 tags.push(su_ds.getBMTagFromCatid(row.catid));
  7182.         }
  7183.     }
  7184.     
  7185.     return (tags.length) ? tags : null;
  7186. }
  7187.  
  7188. function su_add_thumbup_bookmark(urlid, title, catid)
  7189. {
  7190.     var db = su_ds.getDatabase();
  7191.     var bms = su_ds.getBookmarksService();
  7192.     var ts = su_ds.getTaggingService();
  7193.     var tags = su_get_db_tags(urlid, true, true, su_ds.getValue("$sync_bm_adult"));
  7194.     var sql;
  7195.     var result;
  7196.     var row;
  7197.     var result2;
  7198.     var row2;
  7199.     var folderid;
  7200.     var bookmarked;
  7201.     var itemid;
  7202.     var ids;
  7203.     var id;
  7204.     
  7205.     if (! tags)
  7206.         tags = new Array();
  7207.     
  7208.     // get all urls mapped to this urlid
  7209.     sql = "SELECT url FROM url_map WHERE urlid=" + db.q(urlid);
  7210.     result = db.query(sql);
  7211.     while (row = result.shift())
  7212.     {
  7213.         nsiuri = su_get_nsiuri(row.url);
  7214.         
  7215.         ids = bms.getBookmarkIdsForURI(nsiuri, []);
  7216.         
  7217.         bookmarked = false;
  7218.         
  7219.         while (id = ids.shift())
  7220.         {
  7221.             folderid = bms.getFolderIdForItem(id);
  7222.             
  7223.             // if the bookmark is in one of our managed bookmark folders,
  7224.             // remove it
  7225.             sql = "SELECT label FROM supertopic WHERE bm_folderid=" + db.v(folderid);
  7226.             result2 = db.query(sql);
  7227.             if (row2 = result2.shift())
  7228.             {
  7229.                 if (row2.label == su_tagged_folder_name)
  7230.                 {
  7231.                     bms.removeItem(id);
  7232.                     su_check_managed_folder_emptiness(folderid);
  7233.                 }
  7234.                 else
  7235.                     bookmarked = true;
  7236.             }
  7237.         }
  7238.         
  7239.         if (! bookmarked)
  7240.         {
  7241.             folderid = su_get_supertopic_folderid(catid, true);
  7242.             if(folderid)
  7243.             {
  7244.                 itemid = bms.insertBookmark(
  7245.                         folderid,
  7246.                         nsiuri,
  7247.                         bms.DEFAULT_INDEX,
  7248.                         title);
  7249.             }
  7250.         }
  7251.         
  7252.         ts.tagURI(nsiuri, tags);
  7253.     }
  7254. }
  7255.  
  7256. function su_remove_thumbup_bookmark(urlid, title, usertags)
  7257. {
  7258.     var db = su_ds.getDatabase();
  7259.     var bms = su_ds.getBookmarksService();
  7260.     var ts = su_ds.getTaggingService();
  7261.     var autotags = su_get_db_tags(urlid, true, false, true);
  7262.     var sql;
  7263.     var result;
  7264.     var row;
  7265.     
  7266.     // get all urls mapped to this urlid
  7267.     sql = "SELECT url FROM url_map WHERE urlid=" + db.q(urlid);
  7268.     result = db.query(sql);
  7269.     while (row = result.shift())
  7270.     {
  7271.         nsiuri = su_get_nsiuri(row.url);
  7272.         
  7273.         var removed_spec = su_remove_managed_bookmark(nsiuri, autotags);
  7274.         
  7275.         // If the url still has tags and isn't bookmarked
  7276.         // elsewhere, add it to the Unfiled/Tagged folder.
  7277.         
  7278.         if (usertags && (! su_is_bookmarked(nsiuri)))
  7279.         {
  7280.             var timestamp_us;
  7281.             if (removed_spec)
  7282.             {
  7283.                 title = removed_spec.title;
  7284.                 timestamp_us = removed_spec.timestamp_us;
  7285.             }
  7286.             else
  7287.             {
  7288.                 title = (title) ? title : row.url;
  7289.                 timestamp_us = su_get_time_s() + 1000000;
  7290.             }
  7291.             // get all bookmark items mapped to the urlid
  7292.         
  7293.             folderid = su_get_supertopic_folderid(-1, true);
  7294.             if(folderid)
  7295.             {
  7296.                 itemid = bms.insertBookmark(
  7297.                         folderid,
  7298.                         nsiuri,
  7299.                         bms.DEFAULT_INDEX,
  7300.                         title);
  7301.                 
  7302.                 bms.setItemDateAdded(itemid, timestamp_us);
  7303.                 bms.setItemLastModified(itemid, timestamp_us);
  7304.             }
  7305.         }
  7306.         
  7307.         if (usertags)
  7308.             ts.tagURI(nsiuri, usertags);
  7309.         else if (autotags)
  7310.             ts.untagURI(nsiuri, autotags);
  7311.     }
  7312. }
  7313.  
  7314. function su_remove_managed_bookmark(nsiuri, autotags)
  7315. {
  7316.     var db = su_ds.getDatabase();
  7317.     var bms = su_ds.getBookmarksService();
  7318.     var hs = su_ds.getHistoryService();
  7319.     var ts = su_ds.getTaggingService();
  7320.     var folderid;
  7321.     var sql;
  7322.     var result;
  7323.     var query;
  7324.     var ids;
  7325.     var id;
  7326.     var removed_spec = null;
  7327.     
  7328.     ts.untagURI(nsiuri, ["SU"]);
  7329.     if (autotags)
  7330.         ts.untagURI(nsiuri, autotags);
  7331.     
  7332.     ids = bms.getBookmarkIdsForURI(nsiuri, []);
  7333.     
  7334.     while (id = ids.shift())
  7335.     {
  7336.         folderid = bms.getFolderIdForItem(id);
  7337.         // if the bookmark is in one of our managed bookmark folders,
  7338.         // remove it
  7339.         sql = "SELECT label FROM supertopic WHERE bm_folderid=" + db.v(folderid);
  7340.         result = db.query(sql);
  7341.         if (result.length)
  7342.         {
  7343.             removed_spec = new Object();            
  7344.             removed_spec.title = bms.getItemTitle(id);
  7345.             removed_spec.timestamp_us = bms.getItemLastModified(id);
  7346.             bms.removeItem(id);
  7347.             
  7348.             su_check_managed_folder_emptiness(folderid);
  7349.         }
  7350.     }
  7351.     return removed_spec;
  7352. }
  7353.  
  7354. function su_check_managed_folder_emptiness(folderid)
  7355. {
  7356.     var hs = su_ds.getHistoryService();
  7357.     var query;
  7358.     var result;
  7359.     var bms;
  7360.     var db;
  7361.     var sql;
  7362.     // if the managed folder is now empty, remove it.
  7363.     query = hs.getNewQuery();
  7364.     query.setFolders([folderid], 1);
  7365.     result = hs.executeQuery(query, hs.getNewQueryOptions());
  7366.     result.root.containerOpen = true;
  7367.     if (result.root.childCount == 0)
  7368.     {
  7369.         bms = su_ds.getBookmarksService();
  7370.         bms.removeItem(folderid);
  7371.         db = su_ds.getDatabase();
  7372.         sql = "DELETE FROM supertopic WHERE bm_folderid=" + db.v(folderid);
  7373.         db.query(sql);
  7374.     }
  7375. }
  7376.  
  7377. function su_get_rating(url, stumblevideo, opt_url_detail)
  7378. {
  7379.     if (opt_url_detail)
  7380.         return opt_url_detail.rating;
  7381.     
  7382.     if (su_host.places && ! stumblevideo)
  7383.     {
  7384.         var db = su_ds.getDatabase();
  7385.         var result;
  7386.         var row;
  7387.         var sql;
  7388.         sql = "SELECT rating FROM url_map NATURAL JOIN url WHERE url=" + db.q(url);
  7389.         result = db.query(sql);
  7390.         if (row = result.shift())
  7391.         {
  7392.             return (row.rating == -1) ? null : row.rating;
  7393.         }
  7394.         else if ((typeof su_ratings[url]) != "undefined")
  7395.         {
  7396.             // We're generating too many hits.
  7397.             if (! su_ds.lookup("url:rating_getmeta_flag", url))
  7398.             {
  7399.                 su_ds.define("url:rating_getmeta_flag", url, 1);
  7400.                 su_rate_getmeta(url, false);
  7401.             }
  7402.             
  7403.             return su_ratings[url];
  7404.         }
  7405.         else
  7406.         {
  7407.             return null;
  7408.         }
  7409.     }
  7410.     else
  7411.     {
  7412.         if ((typeof su_ratings[url]) == "undefined")
  7413.             return null;
  7414.         else
  7415.             return su_ratings[url];
  7416.     }
  7417. }
  7418.  
  7419. function su_get_tag_list(url)
  7420. {
  7421.     var retval = null;
  7422.     if (((typeof (su_tag_lists_by_url[url])) != "undefined") &&
  7423.             (su_tag_lists_by_url[url] != ""))
  7424.     {
  7425.         retval = su_tag_lists_by_url[url];
  7426.     }
  7427.     else if (su_host.places)
  7428.     {
  7429.         var db = su_ds.getDatabase();
  7430.         var result;
  7431.         var row;
  7432.         var sql;
  7433.         var tags = new Array();
  7434.         sql = "SELECT tag FROM url_map NATURAL JOIN url_tag NATURAL JOIN tag_map WHERE url=" + db.q(url) + " AND url_tag.tagid>1000 AND url_tag.tagid!=" + db.v(su_video_tagid);
  7435.         result = db.query(sql);
  7436.         if (result.length)
  7437.         {
  7438.             while (row = result.shift())
  7439.                 tags.push(row.tag);
  7440.             
  7441.             retval = tags.join(", ");
  7442.             su_tag_lists_by_url[url] = retval;
  7443.         }
  7444.     }
  7445.     return retval;
  7446. }
  7447.  
  7448. // returns true/false is domain is blocked or not
  7449. function su_is_domain_blocked(domain)
  7450. {
  7451.     if (! su_host.places)
  7452.         return false;
  7453.     
  7454.     var out = false;
  7455.     try {
  7456.         var db = su_ds.getDatabase();
  7457.         var sql;
  7458.         var result;
  7459.         sql = "SELECT active FROM blocked_domain WHERE domain=" + db.q(domain) + " AND active=1";
  7460.         result = db.query(sql);
  7461.         out = (result.length) ? true : false;
  7462.     } catch (e) {} // be safe since this is within the stumbling path
  7463.     return out;
  7464. }    
  7465.  
  7466. function su_is_bookmarked(nsiuri)
  7467. {
  7468.     return (PlacesUtils.getMostRecentBookmarkForURI(nsiuri) != -1)
  7469. }
  7470.  
  7471. function su_get_supertopic_folderid(catid, create)
  7472. {
  7473.     var folder_name;
  7474.     if (catid == 0)
  7475.         catid = -1;
  7476.     else if (su_is_adult_category(catid)
  7477.             && (! su_ds.getValue("$sync_bm_adult")))
  7478.         catid = -1;
  7479.     
  7480.     if (catid == -1)
  7481.     {
  7482.         folder_name = su_tagged_folder_name; 
  7483.     }
  7484.     else
  7485.     {
  7486.         folder_name = su_ds.lookup("catid:folder_name", catid);
  7487.         if (! folder_name)
  7488.             return null;
  7489.     }
  7490.             
  7491.     su_verify_bookmarks_folder();
  7492.     
  7493.     var bms = su_ds.getBookmarksService();
  7494.     
  7495.     // If a folder with this name exists in their su bookmarks folder,
  7496.     // use it.
  7497.     
  7498.     var folderid = bms.getChildFolder(
  7499.             su_ds.getValue("$bm_folderid"),
  7500.             folder_name);
  7501.     
  7502.     
  7503.     if (folderid != 0)
  7504.         return folderid;
  7505.     
  7506.     // Otherwise, try to use the most recent one that we created, even
  7507.     // if they moved or renamed it.
  7508.     
  7509.     var db = su_ds.getDatabase();
  7510.     var result;
  7511.     var index;
  7512.     var row;
  7513.     var sql;
  7514.     sql = "SELECT bm_folderid FROM supertopic WHERE label=" + db.q(folder_name);
  7515.     result = db.query(sql);
  7516.     index = -1;
  7517.     if (row = result.shift())
  7518.     {
  7519.         folderid = row.bm_folderid;
  7520.         index = bms.getItemIndex(folderid);
  7521.     }
  7522.     
  7523.  
  7524.     if (index != -1)
  7525.         return folderid;
  7526.     
  7527.     else if (! create)
  7528.         return null;
  7529.     
  7530.     // Do a sanity check to make sure we're allowed to create it.
  7531.     
  7532.     if ((folder_name == "Adult") && (! su_ds.getValue("$sync_bm_adult")))
  7533.         return null;
  7534.     
  7535.     
  7536.     // Create a new one in alphabetical order with our other
  7537.     // automatically generated supertopic folders; make the
  7538.     // 'Other Tagged' folder always last.  
  7539.     
  7540.     index = -1;
  7541.     
  7542.     if (catid != -1)
  7543.     {
  7544.         sql = "SELECT label,bm_folderid FROM supertopic WHERE label>" + db.q(folder_name) + " AND label!="  + db.q(su_tagged_folder_name) + " ORDER BY label LIMIT 1";
  7545.         result = db.query(sql);
  7546.         if (row = result.shift())
  7547.         {
  7548.             try {
  7549.                 index = bms.getItemIndex(row.bm_folderid);
  7550.             } catch (e) {}
  7551.         }
  7552.     }
  7553.     
  7554.     folderid = null;
  7555.     
  7556.     try {
  7557.         folderid = bms.createFolder(
  7558.                 su_ds.getValue("$bm_folderid"),
  7559.                 folder_name,
  7560.                 index);
  7561.         
  7562.         var index2 = bms.getItemIndex(folderid);
  7563.         db.a("INSERT OR REPLACE INTO supertopic (label,bm_folderid) VALUES (");
  7564.         db.as(folder_name);
  7565.         db.alv(folderid);
  7566.         db.query();
  7567.     } catch (e) { su_log_error("CREATE FOLDER", e); }
  7568.     
  7569.     
  7570.     // Update the video query to include this new folder.
  7571.  
  7572.     if (folderid)
  7573.         su_refresh_video_folder_bm();
  7574.     
  7575.     return folderid;
  7576. }
  7577.  
  7578.  
  7579. function su_refresh_video_folder_bm()
  7580. {
  7581.     var db = su_ds.getDatabase();
  7582.     var sql;
  7583.     var result;
  7584.     var row;
  7585.     sql = "SELECT bm_folderid FROM supertopic ORDER BY label";
  7586.     result = db.query(sql);
  7587.     var i;
  7588.     var folderids = new Array();
  7589.     for (i = 0; row = result[i]; i++)
  7590.         folderids.push(row.bm_folderid);
  7591.     
  7592.     var bms = su_ds.getBookmarksService();
  7593.     
  7594.     var itemid = su_ds.getValue("$bm_suvid_itemid");
  7595.     var tmpidx;
  7596.     if (itemid != 0)
  7597.     {
  7598.         tmpidx = -1;
  7599.         try {
  7600.         tmpidx = bms.getItemIndex(itemid);
  7601.         } catch (e) {}
  7602.         if (tmpidx != -1)
  7603.             bms.removeItem(itemid);
  7604.     }
  7605.     
  7606.     itemid = su_add_query_folder_bm(
  7607.             su_ds.getValue("$bm_folderid"),
  7608.             folderids,
  7609.             "video",
  7610.             "Video Favorites",
  7611.             0);
  7612.     
  7613.     su_ds.setValue("$bm_suvid_itemid", itemid);
  7614.     
  7615.     su_ds.flushPrefs();
  7616. }
  7617.  
  7618. function su_get_error_object_dump(o)
  7619. {
  7620.     if (! o)
  7621.         return "\n" + (typeof o);
  7622.     
  7623.     var str = "\n===== dump ===\n"; 
  7624.     var p;
  7625.     for (p in o)
  7626.     {
  7627.         if (p.match(/.*_ERR$/))
  7628.             continue;
  7629.         
  7630.         try {
  7631.             str += "[" + p + "]\n" + o[p] + "\n";
  7632.         }
  7633.         catch (e) {
  7634.             str += "[" + p + "] ERROR\n" + e + "\n";
  7635.         }
  7636.     }
  7637.     str += "========";
  7638.     return str;
  7639. }
  7640.  
  7641. function su_enable_client_features(enable_mask)
  7642. {
  7643.     var old_bits = su_ds.getValue("@client_form");
  7644.     
  7645.     // add new enable routines immediately above
  7646.     
  7647.     su_ds.setValue("@client_form", (old_bits | enable_mask));
  7648. }
  7649.  
  7650. function su_disable_client_features(disable_mask)
  7651. {
  7652.     var old_bits = su_ds.getValue("@client_form");
  7653.  
  7654.     // add new disable routines immediately above
  7655.     
  7656.     su_ds.setValue("@client_form", (old_bits & (~ disable_mask)));
  7657. }
  7658.  
  7659. function su_enable_user_features(enable_mask)
  7660. {
  7661.     var old_bits = su_ds.getValue("$form");
  7662.     
  7663.     if (su_ds.hasFeature("$sociallinks", enable_mask) &&
  7664.             (! su_ds.hasFeature("$sociallinks", old_bits)))
  7665.     {
  7666.         var searchlinks_enabled = 
  7667.                 (su_ds.getValue("$show_searchlinks_score") ||
  7668.                 su_ds.getValue("$show_searchlinks_friends") ||
  7669.                 su_ds.getValue("$show_searchlinks_topic"));
  7670.  
  7671.         su_ds.setValue("$shown_searchlinks_dialog", searchlinks_enabled);
  7672.         if (! searchlinks_enabled)
  7673.             su_ds.setValue("$intro_count", 0);
  7674.     }
  7675.     
  7676.     if (su_ds.hasFeature("$adultrrecat", enable_mask) &&
  7677.             (! su_ds.hasFeature("$adultrrecat", old_bits)))
  7678.     {
  7679.         su_ds.setValue("$recat_adult", 1);
  7680.     }
  7681.     
  7682.     if (su_ds.hasFeature("$adultxrecat", enable_mask) &&
  7683.             (! su_ds.hasFeature("$adultxrecat", old_bits)))
  7684.     {
  7685.         su_ds.setValue("$recat_adult", 2);
  7686.     }
  7687.     
  7688.     if (su_ds.hasFeature("$tagger", enable_mask) &&
  7689.             (! su_ds.hasFeature("$tagger", old_bits)))
  7690.     {
  7691.         su_ds.setValue("$show_tag", true);
  7692.         su_ds.setValue("$show_flag", true);
  7693.         su_ds.setValue("$shown_tag", true);
  7694.         su_init_toolbar_element_visibility();
  7695.     }
  7696.     
  7697.     if (su_ds.hasFeature("$has_subscriptions", enable_mask) &&
  7698.             (! su_ds.hasFeature("$has_subscriptions", old_bits)))
  7699.     {
  7700.         // If they have subscribers, then turn on the stumblers menu.
  7701.         if(!su_ds.getValue("$show_friends_user_changed"))
  7702.         {
  7703.             su_ds.setValue("$show_friends", true);
  7704.             su_set_visible("su_friends", true);
  7705.         }
  7706.     }
  7707.  
  7708.     // add new enable routines immediately above
  7709.     su_ds.setValue("$form", (old_bits | enable_mask));
  7710. }
  7711.  
  7712. function su_disable_user_features(disable_mask)
  7713. {
  7714.     var old_bits = su_ds.getValue("$form");
  7715.  
  7716.     // add new disable routines immediately above
  7717.     
  7718.     su_ds.setValue("$form", (old_bits & (~ disable_mask)));
  7719. }
  7720.  
  7721. function su_process_set_pref_command(name, val_str)
  7722. {
  7723.     switch (su_ds.getPrefType(name))
  7724.     {
  7725.         case "Int":
  7726.             su_ds.setValue(name, parseInt(val_str));
  7727.             break;
  7728.         case "Bool":
  7729.             su_ds.setValue(name, ((val_str == "1") || (val_str == "true")));
  7730.             break;
  7731.         case "Char":
  7732.             su_ds.setValue(name, val_str);
  7733.             break;
  7734.         case "JSON":
  7735.             su_ds.setValue(name, su_ds.deserialize(val_str));
  7736.             break;
  7737.     }
  7738. }
  7739.  
  7740. function su_http_error(error, status)
  7741. {
  7742.     alert("The stumbleupon.com server is currently down.\nPlease try again, and if you are still having difficulties,\ngo to "
  7743.         + su_base_url + "feedback.php to report the problem\nError : " 
  7744.         + error + "\nStatus : " + status);
  7745. }
  7746.  
  7747. // initializes stumbleid and stumblepass; also sets the use_token
  7748. // preference during migration
  7749. function su_init_login(skip_cookies, ignore_cookies)
  7750. {
  7751.     try {
  7752.         if (su_ds.isPrefDefined("@current_user"))
  7753.         {
  7754.             var tmp_id = su_ds.getValue("@current_user");
  7755.             if (tmp_id == "")
  7756.             {
  7757.                 stumbleid = 0;
  7758.                 stumblepass = "";
  7759.             }
  7760.             else
  7761.             {
  7762.                 stumbleid = tmp_id;
  7763.                 stumblepass = su_ds.getStoredPassword();
  7764.                 if ((stumblepass == null) || (stumblepass == ""))
  7765.                 {
  7766.                     try {
  7767.                         su_log_error("NULL PASSWORD");
  7768.                     } catch (e) {}
  7769.                     su_ds.setValue("@current_user", "");
  7770.                     stumbleid = 0;
  7771.                     stumblepass = "";
  7772.                     return false;
  7773.                 }
  7774.             }
  7775.         }
  7776.         else
  7777.         {
  7778.             stumbleid = 0;
  7779.             stumblepass = "";
  7780.         }
  7781.     
  7782.         if (! skip_cookies)
  7783.         {
  7784.             try {
  7785.                 su_process_cookies(ignore_cookies);
  7786.             } catch (e) { su_log_error("INIT COOKIES", e); }
  7787.         }
  7788.         
  7789.     } catch (e) { su_log_error("INIT LOGIN", e);
  7790.         stumbleid = 0;
  7791.         stumblepass = "";
  7792.     }
  7793.     su_ds.getValue("@current_user");
  7794.     su_ds.flushPrefs();
  7795.     return true;
  7796. }
  7797.  
  7798. function su_process_cookies(clear_only)
  7799. {
  7800. var manager = su_get_service(
  7801.                 "@mozilla.org/cookiemanager;1",
  7802.                 "nsICookieManager");
  7803.     var cookies = manager.enumerator;
  7804.     var cookie;
  7805.     var userid1 = null;
  7806.     var password1 = null;
  7807.     var userid2 = null;
  7808.     var password2 = null;
  7809.     var now = (new Date()).getTime();
  7810.     var searchlinks = null;
  7811.     var nickname = null;
  7812.     var enableg = null;
  7813.     var enableu = null;
  7814.     var disableg = null;
  7815.     var disableu = null;
  7816.     var thru_domains = null;
  7817.     
  7818.     while (cookies.hasMoreElements())
  7819.     {
  7820.         cookie = cookies.getNext().QueryInterface(
  7821.                     Components.interfaces.nsICookie);
  7822.                     
  7823.         if ((cookie.host == ("." + su_servername)) &&
  7824.                     ((cookie.expires * 1000) > now))
  7825.         {
  7826.             if (cookie.name == "tsuu")
  7827.             {
  7828.                 userid1 = cookie.value;
  7829.                 manager.remove("." + su_servername, "tsuu", "/", 0);
  7830.             }
  7831.             else if (cookie.name == "tsut")
  7832.             {
  7833.                 // As of 2008-04-15, this is always salted, hashed and
  7834.                 // not encoded.
  7835.                 password1 = cookie.value;
  7836.                 manager.remove("." + su_servername, "tsut", "/", 0);
  7837.             }
  7838.             else if (cookie.name == "stumble_user")
  7839.             {
  7840.                 userid2 = cookie.value;
  7841.                 manager.remove("." + su_servername, "stumble_user", "/", 0);
  7842.             }
  7843.             else if (cookie.name == "stumble_pass")
  7844.             {
  7845.                 // As of 2008-04-15, this is always salted, hashed and
  7846.                 // not encoded.
  7847.                 password2 = cookie.value;
  7848.                 manager.remove("." + su_servername, "stumble_pass", "/", 0);
  7849.             }
  7850.             else if (cookie.name == "nickname")
  7851.             {
  7852.                 nickname = cookie.value;
  7853.                 manager.remove("." + su_servername, "nickname", "/", 0);
  7854.             }
  7855.             else if (cookie.name == "searchlinks")
  7856.             {
  7857.                 searchlinks = true;
  7858.                 manager.remove("." + su_servername, "searchlinks", "/", 0);
  7859.             }
  7860.             else if (cookie.name == "thru_domains")
  7861.             {
  7862.                 thru_domains = cookie.value;
  7863.                 manager.remove("." + su_servername, "thru_domains", "/", 0);
  7864.             }
  7865.             else if (cookie.name == "enableu")
  7866.             {
  7867.                 enableu = parseInt(cookie.value);
  7868.                 manager.remove("." + su_servername, "enableu", "/", 0);
  7869.             }
  7870.             else if (cookie.name == "enableg")
  7871.             {
  7872.                 enableg = parseInt(cookie.value);
  7873.                 manager.remove("." + su_servername, "enableg", "/", 0);
  7874.             }
  7875.             else if (cookie.name == "disableu")
  7876.             {
  7877.                 disableu = parseInt(cookie.value);
  7878.                 manager.remove("." + su_servername, "disableu", "/", 0);
  7879.             }
  7880.             else if (cookie.name == "disableg")
  7881.             {
  7882.                 disableg = parseInt(cookie.value);
  7883.                 manager.remove("." + su_servername, "disableg", "/", 0);
  7884.             }
  7885.             else if (clear_only && ((typeof cookie.name) == "string") &&
  7886.                     (cookie.name.indexOf("NSC_") == 0))
  7887.             {
  7888.                 manager.remove("." + su_servername, cookie.name, "/", 0);
  7889.             }
  7890.         }
  7891.     }
  7892.     
  7893.     if (clear_only)
  7894.         return null;
  7895.  
  7896.     var profile_change = null;
  7897.     
  7898.     if ((userid1 != null) && (password1 != null) &&
  7899.                 (userid1 != "") && (password1 != ""))
  7900.     {
  7901.         var login = true;
  7902.         if ((stumbleid != 0) && (stumblepass != ""))
  7903.         {
  7904.             var name = su_ds.getValue("$nick");
  7905.             if (name == "")
  7906.                 name += stumbleid;
  7907.             
  7908.             if (su_ds.getValue("~visited_signup"))
  7909.             {
  7910.                 login = true;
  7911.             }
  7912.             else
  7913.             {
  7914.                 login = window.confirm("Do you want to sign-in to this new account?\n\n")
  7915.             }
  7916.         }
  7917.         
  7918.         if (login)
  7919.         {
  7920.             profile_change = new Object();
  7921.             stumbleid = userid1;
  7922.             su_ds.setValue("@current_user", stumbleid);
  7923.             profile_change.new_profile = (! su_ds.isPrefDefined("$nick"));
  7924.             stumblepass = password1;
  7925.             su_ds.storePassword(stumblepass, null);
  7926.         }
  7927.     }
  7928.     else if ((userid2 != null) && (password2 != null) &&
  7929.                 (userid2 != "") && (password2 != ""))
  7930.     {
  7931.         profile_change = new Object();
  7932.         stumbleid = userid2;
  7933.         su_ds.setValue("@current_user", stumbleid);
  7934.         profile_change.new_profile = (! su_ds.isPrefDefined("$nick"));
  7935.         if (password2.length < 28)
  7936.         {
  7937.             if (su_enable_hashed_password)
  7938.             {
  7939.                 stumblepass = su_ds.getEncodedPassword(password2, stumbleid);
  7940.                 su_ds.storePassword(stumblepass, null);
  7941.             }
  7942.             else
  7943.             {
  7944.                 stumblepass = password2;
  7945.                 su_ds.storePassword(null, stumblepass);
  7946.             }
  7947.         }
  7948.         else
  7949.         {
  7950.             stumblepass = password2;
  7951.             su_ds.storePassword(stumblepass, null);
  7952.         }
  7953.     }
  7954.     
  7955.     if (stumbleid != 0)
  7956.     {
  7957.         if (searchlinks)
  7958.         {
  7959.             su_ds.setValue("$show_searchlinks_friends", true);
  7960.             su_ds.setValue("$show_searchlinks_score", true);
  7961.             su_ds.setValue("$shown_searchlinks", true);
  7962.         }
  7963.         
  7964.         if (nickname)
  7965.             su_ds.setValue("$nick", nickname);
  7966.         
  7967.         if (enableg)
  7968.             su_enable_client_features(enableg);
  7969.         
  7970.         if (enableu)
  7971.             su_enable_user_features(enableu);
  7972.         
  7973.         if (disableg)
  7974.             su_disable_client_features(disableg);
  7975.         
  7976.         if (disableu)
  7977.             su_disable_user_features(disableu);
  7978.         
  7979.         if (thru_domains)
  7980.             su_ds.setValue("$default_thru_domain_list", thru_domains);
  7981.         
  7982.         manager.remove("." + su_servername, "SU_REMEMBER", "/", 0);
  7983.     }
  7984.     
  7985.     if (profile_change)
  7986.         su_visited_login_page = false;
  7987.     
  7988.     return profile_change;
  7989. }
  7990.  
  7991. // used by logout and handle_window_load to clear authentication
  7992. function su_logout_auth()
  7993. {
  7994.     // 1. remove username and password
  7995.     su_ds.setValue("@current_user", "");
  7996.     su_ds.deleteStoredPassword();
  7997.  
  7998.     // now sync this stuff before we crash
  7999.     su_ds.flushPrefs();
  8000.  
  8001.     // 2. change current user to 0
  8002.     stumbleid = 0;
  8003.     stumblepass = '';
  8004.  
  8005.     // 3. remove cookies stumble_user, stumble_pass, and PHPSESSID
  8006.     // ??? or maybe just all cookies from stumbleupon.com?
  8007.  
  8008.     var cookieManager = su_get_service(
  8009.                 "@mozilla.org/cookiemanager;1",
  8010.                 "nsICookieManager");
  8011.     cookieManager.remove("." + su_servername, "PHPSESSID", "/", 0);
  8012.     cookieManager.remove("." + su_servername, "stumble_user", "/", 0);
  8013.     cookieManager.remove("." + su_servername, "stumble_pass", "/", 0);
  8014.     cookieManager.remove("." + su_servername, "SU_REMEMBER", "/", 0);
  8015.     
  8016.     su_logout_server();
  8017. }
  8018.  
  8019.  
  8020. function su_logout_server()
  8021. {
  8022.     su_post_url_server_async(
  8023.                 "session.php",
  8024.                 su_arp("", "logout", 1),
  8025.                 15000,
  8026.                 su_generic_done);
  8027. }
  8028.  
  8029.  
  8030. // used by signup_page() to grab a new stumbleid from the server
  8031. // and to initialize stumbleid, stumblepass and nick
  8032. function su_init_new_user(challenge, init_toolbar)
  8033. {
  8034.     var detail = new Object();
  8035.     detail.init_toolbar = init_toolbar;
  8036.     // We have no ID yet, hit getid.php
  8037.     su_post_url_server_async(
  8038.                 "init_user.php",
  8039.                 "challenge=" + challenge + 
  8040.                     ((su_enable_hashed_password) ? "&hashed=1" : ""), 
  8041.                 null,
  8042.                 su_init_new_user_done,
  8043.                 detail);
  8044. }
  8045.  
  8046. function su_init_new_user_done(res)
  8047. {
  8048.     var msg = "StumbleUpon was unable to create an account for you.  Please try again later.";
  8049.     
  8050.     try {
  8051.         if (res.status == 1)
  8052.         {
  8053.             alert(msg);
  8054.             return;
  8055.         }
  8056.     } catch (e) {
  8057.         alert(msg);
  8058.         return;
  8059.     }
  8060.  
  8061.     if (res.status != 200)
  8062.     {
  8063.         su_http_error(res.error, res.status);
  8064.         return;
  8065.     }
  8066.     
  8067.     var detail = res.detail;
  8068.     
  8069.     var s = "";
  8070.     if (typeof(res.responseText) != "undefined")
  8071.         s = res.responseText;
  8072.     
  8073.     if (su_log_communication)
  8074.         su_log("response init_user.php", s);
  8075.     
  8076.     var parsed = s.split("\n");
  8077.     // Iterate through commands
  8078.     
  8079.     for (var i = 0; i < parsed.length; i++)
  8080.     {
  8081.         if (parsed[i] == "")
  8082.             continue;
  8083.  
  8084.         // Parse command structure
  8085.         var command = parsed[i].split(" ");
  8086.         switch(command[0])
  8087.         {
  8088.             case "USER":
  8089.                 stumbleid = command[1];
  8090.                 su_ds.setValue("@current_user", stumbleid);
  8091.                 break;
  8092.             case "PASS":
  8093.                 stumblepass = command[1];
  8094.                 break;
  8095.             default:
  8096.                 var context = new Object();
  8097.                 su_process_command(parsed[i], context, command);
  8098.                 if (context.error)
  8099.                     return;
  8100.                 break;
  8101.         }
  8102.     }
  8103.     
  8104.     if (su_isInt(stumbleid) && stumbleid != 0 && stumblepass != 0 && stumbleid != false && stumblepass != false && stumblepass.length>0)
  8105.     {
  8106.         su_ds.storePassword(stumblepass, null);
  8107.         
  8108.         su_store_user_interests();
  8109.         
  8110.         // sync prefs.js in case we crash
  8111.         su_ds.flushPrefs();
  8112.         
  8113.         if (detail.init_toolbar)
  8114.         {
  8115.             var login_detail = new Object();
  8116.             login_detail.skip_cookies = false;
  8117.             login_detail.ignore_cookies = true;
  8118.             login_detail.new_user_prompt = true;
  8119.             login_detail.new_profile = true;
  8120.             su_invoke_global_event("login", login_detail);
  8121.         }
  8122.     }
  8123.     else
  8124.     {
  8125.         // spit out an error
  8126.         alert("StumbleUpon was unable to create an account for you.  Please try again later.");
  8127.     }
  8128. }
  8129.  
  8130. //!!! sometimes fails  0 = notint ???
  8131. function su_isInt(elm) 
  8132. {
  8133.     elm = elm.toString();
  8134.     var pattern = /[^0-9]/;
  8135.     if (pattern.test(elm))
  8136.         return false;
  8137.     else
  8138.         return true;
  8139. }
  8140.  
  8141.  
  8142. // user_cat = incat stumble category ID
  8143. // Gets an url the users hasn't seen yet from stumbleurls
  8144. function su_get_unseen_url(user_cat, hit_server, callback, context)
  8145. {
  8146.     // load stumbles...
  8147.     try {
  8148.         su_load_stumbles(null);
  8149.     } catch (e) { su_log_error("UNSEEN LOAD", e); }
  8150.     
  8151.     if (stumbles.length == 0)
  8152.     {
  8153.         if (hit_server)
  8154.         {
  8155.             // We need to hit the server to get urls
  8156.             if (! context)
  8157.                 context = new su_AsyncContext();
  8158.  
  8159.             context.callbacks.push(callback);
  8160.             
  8161.             su_update_url_cache(
  8162.                         user_cat,
  8163.                         false,
  8164.                         su_get_unseen_url_done,
  8165.                         context);
  8166.  
  8167.             // Did we get any urls from server?
  8168.             if (stumbles.length == 0)
  8169.                 return false;
  8170.         }
  8171.         else
  8172.         {
  8173.             // we're out of stumbles and we're not hitting the server, so bail
  8174.             return false;
  8175.         }
  8176.     }
  8177.     else
  8178.     {
  8179.         // we have stumbles in our queue, carry on
  8180.         su_get_unseen_url_done('', callback, context);
  8181.     }
  8182.     return true;
  8183. }
  8184.  
  8185. function su_get_unseen_url_done(error, callback, context)
  8186. {
  8187.     if (error == "error")
  8188.     {
  8189.         if (callback)
  8190.             callback("error", context);
  8191.         return;
  8192.     }
  8193.     su_load_stumbles(null);
  8194.     
  8195.     var i;
  8196.     for (i = 0; i < stumbles.length; i++)
  8197.     {
  8198.         // Go through each seen url to see if there's one we haven't seen already
  8199.         if (stumbles[i] == "")
  8200.             continue;
  8201.         
  8202.         if (callback)
  8203.             callback(stumbles[i], context);
  8204.         return;
  8205.     }
  8206.  
  8207.     if (callback)
  8208.         callback("", context);
  8209. }
  8210.  
  8211. function clickstumble(event)
  8212. {
  8213.     if (su_promo_mode && (stumbleid == 0))
  8214.     {
  8215. //        var user_cat = su_selected_category;
  8216. //        user_cat += "";
  8217. //        
  8218. //        if (! user_cat)
  8219. //            user_cat = "0";
  8220. //        
  8221. //        var new_cat_flag = (user_cat != su_ds.getValue("$last_incat"));
  8222. //        su_ds.setValue("$last_incat", user_cat);
  8223. //    
  8224. //        var norm_cat = su_trim(user_cat.toLowerCase());
  8225. //        if (((norm_cat == "video") || (norm_cat == "videos") || 
  8226. //                    (norm_cat == "tag_video") || (norm_cat == "tag_videos")) &&
  8227. //                    (su_host.version != "0.0"))
  8228. //        {
  8229. //            su_stumble_video(su_new_tab(event));
  8230. //        }
  8231. //        else
  8232. //        {
  8233.             su_handle_promo_click(event, "stumble");
  8234. //        }
  8235.         return;
  8236.     }
  8237.     
  8238.     stumble(su_new_tab(event));
  8239. }
  8240.  
  8241. function su_AsyncContext()
  8242. {
  8243.     this.callbacks = new Array();
  8244. }
  8245.  
  8246. function su_cancel_stumble_throttle()
  8247. {
  8248.     su_stumble_throttled = false;
  8249. }
  8250.  
  8251. // Handler for button "Stumble"
  8252. function stumble(stumble_new_tab, skip_searchlinks_dialog) 
  8253. {
  8254.     try {
  8255.     var newDate = new Date();
  8256.     var newTime = newDate.getTime();
  8257.     var oldTime = su_ds.getIntValue("$last_stumble");
  8258.     
  8259.     // avoid double-click
  8260.     if (! stumble_new_tab)
  8261.     {
  8262. //!!! Why does this get stuck intermittently for some users?
  8263. //        if (newTime - oldTime < su_ds.getValue("@click_throttle_ms"))
  8264. //            return;
  8265.  
  8266.         if (su_stumble_throttled)
  8267.         {
  8268.             return;
  8269.         }
  8270.         else
  8271.         {
  8272.             su_stumble_throttled = true;
  8273.             setTimeout(
  8274.                 su_cancel_stumble_throttle,
  8275.                 su_ds.getValue("@click_throttle_ms"));
  8276.         }
  8277.     }
  8278.  
  8279.     if (su_cacheTimer != 0)
  8280.     {
  8281.         clearTimeout(su_cacheTimer);
  8282.         su_cacheTimer = 0;
  8283.     }
  8284.  
  8285.     // See if they are not logged in
  8286.     var getit = su_ds.getValue("@current_user");
  8287.     if (! getit)
  8288.     {
  8289.         // okay, they are not logged in        
  8290.  
  8291.         // see if they've already created/used an account with this toolbar
  8292.         if (su_has_logged_in())
  8293.         {
  8294.             su_show_signin_dialog();
  8295.         }
  8296.         else
  8297.         {
  8298.             su_verify_cookie_perms(false);
  8299.             
  8300.             su_set_server_location_signup(false);
  8301.         }
  8302.         su_check_progress_listener();
  8303.         return;
  8304.     }
  8305.     su_check_progress_listener();
  8306.  
  8307.     if (stumbleid == 0)
  8308.         return;
  8309.  
  8310.     if (! skip_searchlinks_dialog)
  8311.     {
  8312.         if (su_show_searchlinks_dialog(true, stumble_new_tab, true))
  8313.             return;
  8314.     }
  8315.     
  8316.     if (! su_ds.getValue("$shown_searchlinks_dialog"))
  8317.         su_ds.incrementValue("$intro_count");
  8318.     
  8319. //    su_update_verified_reporting(true);
  8320.     
  8321.     var user_cat = su_selected_category;
  8322.     
  8323.     if (! user_cat)
  8324.         user_cat = "0";
  8325.     
  8326.     var new_cat_flag = (user_cat != su_ds.getValue("$last_incat"));
  8327.     su_ds.setValue("$last_incat", user_cat);
  8328.     
  8329.     var oldDate = new Date();
  8330.     oldDate.setTime(oldTime);
  8331.  
  8332.     su_ds.setValue("$last_stumble", newTime);
  8333.     if (user_cat == "0")
  8334.         su_ds.setValue("$poll_time_s", su_get_time_s());
  8335.     
  8336.     su_ds.flushPrefs();
  8337.     
  8338.     // change icon...
  8339.     su_get_element("su_stumble").image="chrome://stumbleupon/content/skin/stumble2.png";
  8340.     su_stumble_action_count++;
  8341.     setTimeout(
  8342.                 su_reset_stumble_action_indicator,
  8343.                 su_ds.getValue("@stumble_action_timeout_ms"),
  8344.                 su_stumble_action_count);
  8345.     
  8346.     var norm_cat = su_trim(user_cat.toLowerCase());
  8347.     if (((norm_cat == "video") || (norm_cat == "videos") || 
  8348.                 (norm_cat == "tag_video") || (norm_cat == "tag_videos")) &&
  8349.                 (su_host.version != "0.0"))
  8350.     {
  8351.         su_stumble_video(stumble_new_tab);
  8352.         return;
  8353.     }
  8354.     
  8355.     if (su_stumble_async_context && ((newTime - oldTime) <= 
  8356.                 su_ds.getValue("@recommend_timeout_ms")) &&
  8357.                 (! new_cat_flag))
  8358.     {
  8359.         // If a stumble action is in progress and the category hasn't 
  8360.         // changed, we only simulate stumbling.  Ideally, the time 
  8361.         // comparison above shouldn't be necessary, but we include it as a
  8362.         // failsafe to avoid disabling stumbling if 
  8363.         // su_stumble_async_context somehow doesn't get set to null. 
  8364.         // -- JW
  8365.  
  8366.         //!!! It would be better to queue stumble actions if they're in
  8367.         // the same topic and if they're to be opened in new tabs.  But
  8368.         // this would increase likelihood that a referral (and, more 
  8369.         // importantly, a note attached to a referral) may not be seen.
  8370.         // Here are a couple related options:
  8371.         // o Don't consider a referral to have been seen unless the
  8372.         //   person lingers on the relevant tab.
  8373.         // o Highlight tabs featuring referrals that haven't been lingered
  8374.         //   upon.
  8375.         // o If a pending action not targeting a new tab exists, 
  8376.         //   implicitly cancel the non-new-tab action, perhaps by 
  8377.         //   converting it into a new-tab action.
  8378.         // -- JW
  8379.         
  8380.         return;
  8381.     }
  8382.     else if (su_stumble_async_context)
  8383.     {
  8384.         try {
  8385.             // Try shouldn't be necessary, but this eliminates possibility 
  8386.             // of an error in the callback execution path breaking 
  8387.             // stumbling. -- JW
  8388.             if (su_stumble_async_context && su_stumble_async_context._request)
  8389.                 su_service.abortPostAsync(su_stumble_async_context._request);
  8390.         } catch (e) { su_log_error("RECOMMEND ABORT ERROR", e); }
  8391.     }
  8392.  
  8393.     
  8394.     // see if new day is the same as today
  8395.     var newDay = newDate.getDate();
  8396.     var oldDay = oldDate.getDate();
  8397.     var newMonth = newDate.getMonth();
  8398.     var oldMonth = oldDate.getMonth();
  8399.     var newYear = newDate.getYear();
  8400.     var oldYear = oldDate.getYear();
  8401.  
  8402.     if (new_cat_flag)
  8403.     {
  8404.         clear_stumbles();
  8405.     }
  8406.     
  8407.     var first_of_day = false;
  8408.     if (oldTime != 0)
  8409.     {
  8410.         if (oldDay != newDay || oldMonth != newMonth || oldYear != newYear)
  8411.         {
  8412.             first_of_day = true;
  8413.             // clear stumbles
  8414.             clear_stumbles();
  8415.         }
  8416.         else if (newTime - oldTime > 1000 * 60 * 60 * 2)
  8417.         {
  8418.             // clear stumbles if you haven't stumbled in the last 2 hours
  8419.             // so our stumbles are "fresh"
  8420.             clear_stumbles();
  8421.         }
  8422.     }
  8423.  
  8424.     
  8425.     var target_browser = null;
  8426.     if (! stumble_new_tab)
  8427.         target_browser = getBrowser().selectedBrowser;
  8428.  
  8429.  
  8430.     if (typeof(user_cat) == "number" || typeof(user_cat) == "undefined" || user_cat == null || user_cat.indexOf("TAG") == -1)
  8431.     {
  8432.         // clear search/tag box
  8433.         su_old_search = '';
  8434.         su_get_element("su_searchbox").value = '';
  8435.         su_last_typed_tag = 0;
  8436.     }
  8437.     else
  8438.     {
  8439.         // put it in the box
  8440.         if (user_cat.indexOf("TAG_") == 0)
  8441.         {
  8442.             var tmp_cat = user_cat.substr(4);
  8443.  
  8444.             // Don't tag with thru domains.
  8445.             tag = su_ds.isThruDomain(tmp_cat) ? "" : tmp_cat;
  8446.         }
  8447.         else if (user_cat.indexOf("USERTAG_") == 0)
  8448.         {
  8449.             var chunk = user_cat.substr(8);
  8450.             chunks = chunk.split('_');
  8451.             var tag = chunks[1];
  8452.             var profile = chunks[0];
  8453.         }
  8454.         else
  8455.         {
  8456.             tag = '';    
  8457.         }
  8458.         su_get_element("su_searchbox").value=tag;
  8459.         su_get_element("su_searchbox").removeAttribute("mode");
  8460.         su_old_search = tag;
  8461.         su_last_typed_tag = 0;
  8462.         su_visited_searchbox = 1;
  8463.     }
  8464.     
  8465.  
  8466.     var unseen = "";
  8467.  
  8468.     var context = new su_AsyncContext();
  8469.     context.user_cat = user_cat;
  8470.     context.timestamp = newTime;
  8471.     context.new_tab = stumble_new_tab;
  8472.     context.target_browser = target_browser;
  8473.     context.quiet = false;
  8474.     context.stumblevideo = false;
  8475.     context.first_of_day = first_of_day;
  8476.     context.skip_count = 0;
  8477.  
  8478.     su_stumble_async_context = context;
  8479.     su_get_unseen_url(
  8480.                 user_cat,
  8481.                 1,
  8482.                 function(unseen, context) { window.stumble_done(unseen, context); },
  8483.                 context);
  8484.     
  8485.     
  8486.     } catch (e) {
  8487.         if (stumbleid == 0)
  8488.             su_log_error("STUMBLE LOGGED-OUT", e);
  8489.         else
  8490.             su_log_error("STUMBLE LOGGED-IN", e, su_ds.getValue("$last_incat"), su_service.getErrorObjectDump(su_stumble_async_context));
  8491.         su_stumble_async_context = null;
  8492.     }
  8493. }
  8494.  
  8495. function su_stumble_video(new_tab)
  8496. {
  8497.     var label;
  8498.     if (!(su_promo_mode && (stumbleid == 0)))
  8499.     {
  8500.         su_set_mode("video", "Video",
  8501.                     "chrome://stumbleupon/content/skin/video.png",
  8502.                     "Stumble! ", "Stumble a video");
  8503.     }
  8504.     
  8505.     if (new_tab)
  8506.     {
  8507.         su_pending_stumblevideo_stumble = true;
  8508.         su_set_location(
  8509.                     "http://video." + su_servername + "/",
  8510.                     null,
  8511.                     true);
  8512.     }
  8513.     else if (su_is_matching_domain(su_get_browser_url(null, true), 
  8514.                 "video." + su_servername))
  8515.     {
  8516.         su_dispatch_click(getBrowser().contentDocument, "stumbleButton");
  8517.     }
  8518.     else
  8519.     {
  8520.         su_pending_stumblevideo_stumble = true;
  8521.         var params = null;
  8522.         if (su_host.dist)
  8523.             params = su_arp("", "dist", su_host.dist);
  8524.         su_set_location(
  8525.                     "http://video." + su_servername + "/",
  8526.                     params,
  8527.                     false);
  8528.     }
  8529. }
  8530.  
  8531. function su_update_message(tab_url_detail, url_detail, url, tld, stumblevideo)
  8532. {
  8533.     if (! tab_url_detail)
  8534.         return;
  8535.     
  8536.     if (! tab_url_detail.messageid)
  8537.         return;
  8538.     
  8539.     var id = "su_messageOuterBox" + tab_url_detail.messageid;
  8540.     
  8541.     if (su_drawer_timers[id])
  8542.         return;
  8543.     
  8544.     var el;
  8545.     if (url_detail == tab_url_detail)
  8546.     {
  8547.         el = su_get_element("su_bannerReloadButton" + tab_url_detail.messageid);
  8548.         if (el)
  8549.             el.disabled = true;
  8550.     }
  8551.     else if (stumblevideo && (url != tab_url_detail.url))
  8552.     {
  8553.         su_close_message(tab_url_detail.messageid, true);
  8554.     }
  8555.     else if ((! stumblevideo) && (tab_url_detail.tld != tld))
  8556.     {
  8557.         su_close_message(tab_url_detail.messageid, true);
  8558.     }
  8559.     else
  8560.     {
  8561.         el = su_get_element("su_bannerReloadButton" + tab_url_detail.messageid);
  8562.         if (el)
  8563.             el.disabled = false;
  8564.     }
  8565. }
  8566.  
  8567. /*
  8568. function su_update_verified_reporting(enable_reporting)
  8569. {
  8570.     if (su_enable_freereporting)
  8571.         return;
  8572.     
  8573.     // people can't report a stumble as 404/spam until they actually stumble
  8574.     var disabled = (enable_reporting) ? "false" : "true";
  8575.     
  8576.     su_get_element("su_report-menu").setAttribute("disabled", disabled);
  8577.     su_get_element("su_flag_adult").setAttribute("disabled", disabled);
  8578.     su_get_element("su_flag_wrongtopic").setAttribute("disabled", disabled);
  8579.     su_get_element("su_flag_duplicate").setAttribute("disabled", disabled);
  8580.     su_get_element("su_flag_inaccurate").setAttribute("disabled", disabled);
  8581.     su_get_element("su_flag_spam").setAttribute("disabled", disabled);
  8582.     su_get_element("su_flag_broken").setAttribute("disabled", disabled);
  8583.     su_get_element("su_flag_wronglanguage").setAttribute("disabled", disabled);
  8584. }
  8585. */
  8586.  
  8587. function su_update_comment_level(url_detail, rateable)
  8588. {
  8589.     if (url_detail && url_detail.comment_level)
  8590.         su_set_image("su_website_info", "chrome://stumbleupon/content/skin/bubble" + url_detail.comment_level + ".png");
  8591.     
  8592.     else if (rateable)
  8593.         su_set_image("su_website_info", "chrome://stumbleupon/content/skin/bubble.png");
  8594.     
  8595.     else
  8596.         su_set_image("su_website_info", "chrome://stumbleupon/content/skin/bubblex.png");
  8597. }
  8598.  
  8599. function su_update_referral_menu_tooltip(url_detail, stumblevideo)
  8600. {
  8601.     var el = su_get_element("su_referral_menu");
  8602.     
  8603.     if (! url_detail)
  8604.     {
  8605.         el.setAttribute("tooltiptext", "Share this page");
  8606.         return;
  8607.     }
  8608.     
  8609.     if (stumblevideo)
  8610.         el.setAttribute("tooltiptext", "Share this video");
  8611.     
  8612.     else if (url_detail.catid == 302)
  8613.         el.setAttribute("tooltiptext", "Share this picture");
  8614.     
  8615.     else
  8616.         el.setAttribute("tooltiptext", "Share this page");
  8617. }
  8618.  
  8619. function su_update_firstrater(url_detail)
  8620. {
  8621.     if (! url_detail)
  8622.     {
  8623.         su_set_visible("firstrater", false);
  8624.         su_set_visible("su_sponsor", false);
  8625.         su_set_image("su_website_info",
  8626.                     "chrome://stumbleupon/content/skin/bubble.png");
  8627.         su_set_image("su_referral_menu", 
  8628.                     "chrome://stumbleupon/content/skin/icon_tb_share.png");
  8629.         return;
  8630.     }
  8631.  
  8632.     if ((url_detail.relationship == "sponsored") || 
  8633.                 (url_detail.relationship == "friend-sponsored"))
  8634.     {
  8635.         // sponsor
  8636.     
  8637.         // Set and show sponsor button
  8638.         su_set_visible("su_sponsor", true);
  8639.         frater = su_get_element("su_sponsor");
  8640.         frater.setAttribute("tooltiptext", "This site is sponsored");
  8641.     }
  8642.     else
  8643.     {
  8644.         // nonsponsor
  8645.     
  8646.         // Hide sponsor button
  8647.         su_set_visible("su_sponsor", false);
  8648.     }
  8649.  
  8650.     if (! url_detail.firstrater_nick)
  8651.     {
  8652.         // Hide firstrater button
  8653.         su_set_visible("firstrater", false);
  8654.         return;
  8655.     }
  8656.     
  8657.     // Set and show firstrater button
  8658.     frater = su_get_element("firstrater");
  8659.     
  8660.     su_set_visible("firstrater", true);
  8661.     
  8662.     var tooltip = url_detail.firstrater_nick;
  8663.     
  8664.     su_set_label("firstrater", url_detail.firstrater_nick);
  8665.     
  8666.     switch (url_detail.relationship)
  8667.     {
  8668.         case "referral":
  8669.             // this site was sent directly to you by a friend    
  8670.             frater.image = "chrome://stumbleupon/content/skin/redman.png";
  8671.             tooltip += " who sent you: ";
  8672.             break;
  8673.             
  8674.         case "friend":
  8675.             // your friend rate this site    
  8676.             frater.image = "chrome://stumbleupon/content/skin/redman.png";
  8677.             tooltip += " who recommends: ";
  8678.             break;
  8679.         
  8680.         case "friend-sponsored":
  8681.             frater.image = "chrome://stumbleupon/content/skin/redman.png";
  8682.             tooltip += " who suggested: ";
  8683.             break;
  8684.             
  8685.         case "sponsored":
  8686.             // a non friend rated this site    
  8687.             frater.image = "chrome://stumbleupon/content/skin/firstrater.png";
  8688.             tooltip += " who recommends: ";
  8689.             break;
  8690.     
  8691.         case "firstrater":
  8692.             // a non friend rated this site    
  8693.             frater.image = "chrome://stumbleupon/skin/firstrater.png";
  8694.             tooltip += " who suggested: ";
  8695.             break;
  8696.     }
  8697.  
  8698.     tooltip += url_detail.url;
  8699.  
  8700.     frater.firstrater = url_detail.firstrater_nick;
  8701.     frater.setAttribute("tooltiptext", tooltip);
  8702. }
  8703.  
  8704. function su_update_thru_domain(url, tld, url_detail, stumblevideo, from_resource_installed)
  8705. {
  8706.     if (! url)
  8707.         return;
  8708.  
  8709.     if (! tld)
  8710.         tld = su_get_tld(url);
  8711.     
  8712.     if ((! tld) || (url_detail && stumblevideo)) 
  8713.     {
  8714.         su_set_visible("su_mode_domain", false);
  8715.         su_set_image("su_mode_domain",
  8716.                     "chrome://stumbleupon/content/skin/topic.png");
  8717.         return;
  8718.     }
  8719.     
  8720.     var tld_parts = tld.split(".");
  8721.     
  8722.     var i = 0;
  8723.     var domain = null;
  8724.     var cmp = "";
  8725.     while (tld_parts.length)
  8726.     {
  8727.         var part = tld_parts.pop();
  8728.         if (part == "")
  8729.             return;
  8730.         
  8731.         if (i == 0)
  8732.             cmp = "." + part;
  8733.         else if (i == 1)
  8734.             cmp = part + cmp;
  8735.         else
  8736.             cmp = part + "." + cmp;
  8737.         
  8738.         if (su_ds.isThruDomain(cmp))
  8739.             domain = cmp;
  8740.         
  8741.         i++;
  8742.     }
  8743.  
  8744.     if (domain)
  8745.     {
  8746.         if (su_get_element("su_mode_dyn_" + su_get_channel_id(domain)))
  8747.             domain = null;
  8748.     }
  8749.     
  8750.     if ((domain == "wikipedia.org") && 
  8751.                 su_ds.getValue("$show_mode_wiki"))
  8752.         domain = null;
  8753.     
  8754.     if (! domain)
  8755.     {
  8756.         su_set_visible("su_mode_domain", false);
  8757.         su_set_image("su_mode_domain",
  8758.                     "chrome://stumbleupon/content/skin/topic.png");
  8759.         
  8760.         if (su_info_spec && su_info_spec.domain)
  8761.             su_hide_info();
  8762.         
  8763.         return;
  8764.     }
  8765.     
  8766.     var favicon_url = su_get_favicon_url(domain);
  8767.     
  8768.     if (favicon_url)
  8769.     {
  8770.         su_set_image("su_mode_domain", favicon_url);
  8771.     }
  8772.     else
  8773.     {
  8774.         su_set_image("su_mode_domain",
  8775.                     "chrome://stumbleupon/content/skin/domain.png");
  8776.     }
  8777.     su_set_visible("su_mode_domain", true);
  8778.     var el = su_get_element("su_mode_domain");
  8779.     el.setAttribute("onclick", "su_handle_domain_mode_click(event, '" + domain + "');");
  8780.     el.setAttribute("tooltiptext", "Stumble a page from " + domain);
  8781.     
  8782.     if (stumblevideo)
  8783.         return;
  8784.     
  8785.     if (from_resource_installed)
  8786.         return;
  8787.     
  8788.     if (su_ds.getValue("$shown_thru_domain_info_count") >= su_ds.getValue("~shown_thru_domain_info_count_max"))
  8789.         return;
  8790.     
  8791.     var domains = su_ds.getValue("$shown_thru_domain_info_list").split(":");
  8792.     for (i = 0; i < domains.length; i++)
  8793.     {
  8794.         if (domains[i] == "")
  8795.             continue;
  8796.         
  8797.         if (domains[i] == domain)
  8798.             return;
  8799.     }
  8800.     
  8801.     su_display_info("thru_domain", domain);
  8802. }
  8803.  
  8804. function su_update_topic_and_reporting(tab_url_detail, url_detail, tld, from_stumbled, rec_url)
  8805. {
  8806.     
  8807.     var el = su_get_element("su_morefrom");
  8808.  
  8809.     if (el && url_detail && url_detail.topic_name)
  8810.     {
  8811.         el.setAttribute("label", "More from " + url_detail.topic_name);
  8812.         el.setAttribute("tooltiptext", "More from " + url_detail.topic_name);
  8813.         el.setAttribute("hidden", "false");
  8814.         el.setAttribute("oncommand", "su_select_topic(" + 
  8815.                     url_detail.catid + ",'" + url_detail.topic_name + "', false);");
  8816.     }    
  8817.     else if (el)
  8818.     {
  8819.         el.setAttribute("hidden", "true");
  8820.     }
  8821.  
  8822.     // Define the topic button used for display
  8823.  
  8824.     var topics_style = su_ds.getValue("$stumble_topics_style");
  8825.     
  8826.     var menu_style = (topics_style != 2);
  8827.     
  8828.     // Set the information to the topic button
  8829.     
  8830.     var report_menu = su_get_element("su_stumble_report_menu"); 
  8831.     
  8832.     if (menu_style && su_ds.getValue("$stumble_topics"))
  8833.     {
  8834.         su_set_visible("su_stumble_topic", false);
  8835.         
  8836.         var widget_id;
  8837.         
  8838.         switch (topics_style)
  8839.         {
  8840.             case 0: widget_id = "su_stumble_topic_menu_left";  break;
  8841.             case 1: widget_id = "su_stumble_topic_menu_right"; break;
  8842.         }
  8843.         
  8844.         if ((url_detail && url_detail.cur_topic_name) ||
  8845.                 (tab_url_detail && (tab_url_detail.tld == tld) &&
  8846.                 tab_url_detail.cur_topic_name))
  8847.         {
  8848.             var url = (url_detail) ? url_detail.url : tab_url_detail.url;
  8849.             var topic_name = (url_detail) ? url_detail.cur_topic_name : tab_url_detail.cur_topic_name;
  8850.             su_get_element(widget_id + "_popup").removeAttribute("onpopupshowing");
  8851.             su_get_element(widget_id + "_popup").setAttribute("onpopupshowing",
  8852.                     'su_prepare_stumble_topic_menu(event, "' + url + '");');
  8853.             
  8854.             if (tab_url_detail && (tab_url_detail == url_detail))
  8855.                 su_remove_attribute(widget_id, "style");
  8856.             else
  8857.                 su_set_attribute(widget_id, "style", "color: #707070;");
  8858.             
  8859.             if (topics_style == 1)
  8860.                 su_set_visible("su_separator7", true);
  8861.             
  8862.             su_set_label(widget_id, topic_name);
  8863.             su_set_visible(widget_id, true);
  8864.         }
  8865.         else
  8866.         {
  8867.             su_set_visible(widget_id, false);
  8868.             su_set_visible("su_separator7", false);
  8869.         }
  8870.     }
  8871.     else
  8872.     {
  8873.         su_set_visible("su_stumble_topic_menu_left", false);
  8874.         su_set_visible("su_stumble_topic_menu_right", false);
  8875.         
  8876.         if (url_detail && url_detail.cur_topic_name && su_ds.getValue("$stumble_topics"))
  8877.         {
  8878.             su_set_label("su_stumble_topic", url_detail.cur_topic_name);
  8879.             su_get_element("su_stumble_topic").removeAttribute("onclick");
  8880.             su_get_element("su_stumble_topic").setAttribute("onclick", 
  8881.                     'su_handle_stumble_topic_click(event, "' + url_detail.url + '");');
  8882.             su_set_visible("su_stumble_topic", true);
  8883.             su_set_visible("su_separator7", true);
  8884.         }
  8885.         else
  8886.         {
  8887.             su_set_visible("su_stumble_topic", false);
  8888.             su_set_visible("su_separator7", false);
  8889.         }
  8890.     }
  8891.     
  8892.         
  8893.     if ((url_detail && url_detail.cur_topic_name) ||
  8894.             (tab_url_detail && (tab_url_detail.tld == tld)) ||
  8895.             rec_url)
  8896.     {
  8897.         var url;
  8898.         if (url_detail)
  8899.             url = url_detail.url;
  8900.         else if (rec_url)
  8901.             url = rec_url;
  8902.         else
  8903.             url = tab_url_detail.url;
  8904.         
  8905.         su_get_element("su_stumble_report_popup").removeAttribute("onpopupshowing");
  8906.         su_get_element("su_stumble_report_popup").setAttribute("onpopupshowing",
  8907.                 'su_prepare_stumble_report_menu(event, "' + url + '");');
  8908.         report_menu.disabled = false;
  8909.         
  8910.         if (tab_url_detail && (tab_url_detail == url_detail))
  8911.             report_menu.removeAttribute("style");
  8912.         else
  8913.             report_menu.setAttribute("style", "color: #707070;");
  8914.     }
  8915.     else
  8916.     {
  8917.         report_menu.disabled = true;
  8918.     }
  8919.  
  8920.     // Update the separator that may be affected by whether the topic menu is visible.
  8921.     su_set_visible("su_separator_category", su_ds.getValue("$show_topics") || !su_get_element("su_stumble_topic_menu_left").collapsed);
  8922. }
  8923.  
  8924. /*
  8925. function su_update_language(url_detail, from_stumbled)
  8926. {
  8927.     if ((! from_stumbled) && (! su_enable_freereporting))
  8928.         return;
  8929.     
  8930.     // Update language UI elements.
  8931.     if (url_detail && url_detail.language)
  8932.     {
  8933.         su_get_element("su_wronglanguage").label='Wrong Language (currently ' + url_detail.language + ')';
  8934.         su_get_element("su_flag_wronglanguage").label='Flag as Wrong Language (currently ' + url_detail.language + ')';
  8935.     }
  8936.     else
  8937.     {
  8938.         su_get_element("su_wronglanguage").label='Wrong Language';
  8939.         su_get_element("su_flag_wronglanguage").label='Flag as Wrong Language';
  8940.     }
  8941. }
  8942. */
  8943.  
  8944. function su_update_page_feature_prompt(url)
  8945. {
  8946.     var service_detail = su_get_service_meta(url, true);
  8947.     
  8948.     if (su_is_matching_domain("facebook.com"))
  8949.     {
  8950.         if (su_ds.getValue("#checked_facebook"))
  8951.         {
  8952.             if (su_ds.getValue("$facebook_linked"))
  8953.             {
  8954.                 su_set_visible("su_page_feature_prompt", false);
  8955.             }
  8956.             else
  8957.             {
  8958.                 su_set_image("su_page_feature_prompt", "chrome://stumbleupon/content/skin/favicon_facebook.gif");
  8959.  
  8960.                 if (su_ds.getValue("$facebook_added"))
  8961.                     su_set_label("su_page_feature_prompt", "Link your Facebook account");
  8962.                 else
  8963.                     su_set_label("su_page_feature_prompt", "Share using Facebook");
  8964.                     
  8965.                 su_get_element("su_page_feature_prompt").setAttribute("tooltiptext", "Share and browse using the StumbleUpon application on Facebook");
  8966.                 su_set_visible("su_page_feature_prompt", true);
  8967.             }
  8968.         }
  8969.         else
  8970.         {
  8971.             su_get_facebook(null);
  8972.         }
  8973.     }
  8974.     else if (service_detail)
  8975.     {
  8976.         if (0) //su_ds.hasFeature("$slbuttonprompt") &&
  8977. //                (! su_ds.getValue("$show_searchlinks_score")) &&
  8978. //                (! su_ds.getValue("$show_searchlinks_friends")) &&
  8979. //                (! su_ds.getValue("$show_searchlinks_topic")) &&
  8980. //                ((! su_ds.getValue("$shown_searchlinks")) || 
  8981. //                su_ds.hasFeature("$slbuttonpermaprompt")))
  8982.         {
  8983.             su_set_image("su_page_feature_prompt", service_detail.icon);
  8984.             su_set_label("su_page_feature_prompt", service_detail.prompt_label);
  8985.             su_get_element("su_page_feature_prompt").setAttribute("tooltiptext",  service_detail.prompt_tooltip);
  8986.             su_set_visible("su_page_feature_prompt", true);
  8987.         }
  8988.         else
  8989.         {
  8990.             su_set_visible("su_page_feature_prompt", false);
  8991.         }
  8992.     }
  8993.     else
  8994.     {
  8995.         su_set_visible("su_page_feature_prompt", false);
  8996.     }
  8997. }
  8998.  
  8999. function su_update_website_info_promo(url)
  9000. {
  9001.     var service_detail = su_get_service_meta(url, false);
  9002.     
  9003.     if (url.indexOf(su_base_url + "url") == 0)
  9004.         su_get_element("su_website_info_promo").disabled = true;
  9005.     else
  9006.         su_get_element("su_website_info_promo").disabled = false;
  9007.  
  9008.     if (service_detail)
  9009.     {
  9010.         su_search_service_id = service_detail.id;
  9011.         su_set_image("su_website_info_promo", service_detail.icon);
  9012.         su_set_label("su_website_info_promo", service_detail.prompt_label);
  9013.         su_get_element("su_website_info_promo").setAttribute("tooltiptext",  service_detail.prompt_tooltip);
  9014.     }
  9015.     else
  9016.     {
  9017.         su_search_service_id = null;
  9018.         su_set_image("su_website_info_promo", "chrome://stumbleupon/content/skin/bubble.png");
  9019.         su_set_label("su_website_info_promo", su_get_element("su_website_info_promo").getAttribute("showlabel"));
  9020.         su_get_element("su_website_info_promo").setAttribute("tooltiptext",  "People who like this");
  9021.     }
  9022. }
  9023.         
  9024. function su_get_tld(url)
  9025. {
  9026.     return su_service.getEffectiveTLD(url);
  9027. }
  9028.  
  9029. function su_deserialize_url_command_params(unseen, for_load)
  9030. {
  9031.     var field_names = new Array(
  9032.                 "url",                //  1 .
  9033.                 "catid",              //  2
  9034.                 "referrer",           //  3 .
  9035.                 "actual_url",         //  4 .
  9036.                 "firstrater",         //  5
  9037.                 "firstrater_nick",    //  6
  9038.                 "lang_code",          //  7  not mime_type?
  9039.                 "cluster_type",       //  8 .
  9040.                 "urlid",              //  9 .
  9041.                 "publicid",           // 10
  9042.                 "comment_level",      // 11
  9043.                 "rec_type",           // 12
  9044.                 "referral_note",      // 13
  9045.                 "referralid",         // 14 .
  9046.                 "catid2",             // 15
  9047.                 "catid3"              // 16
  9048.                 );
  9049.     
  9050.     var a = unseen.split(" ");
  9051.     var spec = new Object();
  9052.     var i;
  9053.     for (i = 0; i < field_names.length; i++)
  9054.     {
  9055.         if (a.length > 0)
  9056.             spec[field_names[i]] = a.shift();
  9057.         else
  9058.             spec[field_names[i]] = null;
  9059.         
  9060.         if (spec[field_names[i]] == "")
  9061.             spec[field_names[i]] = null;
  9062.     }
  9063.     
  9064.     if (! spec.url)
  9065.         return null;
  9066.     
  9067. //    spec.load_dateobj = null;
  9068.     
  9069.     spec.redirect_url = spec.url;
  9070.     
  9071.     if (spec.url && spec.url != "")
  9072.         spec.tld = su_get_tld(spec.url);
  9073.     
  9074.     if (! spec.tld)
  9075.         spec.tld = "";
  9076.     
  9077.     if (spec.cluster_type)
  9078.         spec.cluster_type = parseInt(spec.cluster_type);
  9079.     
  9080.     if (! spec.urlid)
  9081.         spec.urlid = 0;
  9082.     
  9083.  
  9084.     if (for_load)
  9085.         return spec;
  9086.     
  9087.     
  9088.     spec.sender = (spec.firstrater_nick) ? 
  9089.                 spec.firstrater_nick : spec.firstrater;
  9090.     
  9091.     spec.is_system_referral = ((spec.cluster_type == 4) &&
  9092.                 spec.sender && 
  9093.                 (spec.sender.toLowerCase() == "stumbleupon"));
  9094.     
  9095.     spec.is_friend_referral = ((spec.cluster_type == 4) && 
  9096.                 (! spec.is_system_referral));
  9097.     
  9098.     if (spec.referral_note)
  9099.     {
  9100.         try {
  9101.             spec.referral_note = decodeURIComponent(spec.referral_note);
  9102.             if (spec.referral_note.length > 5000)
  9103.                 spec.referral_note = spec.referral_note.substring(0, 4999);
  9104.         }
  9105.         catch (e) {
  9106.             spec.referral_note = null;
  9107.             su_log_error("BAD REFERRALNOTE", e);
  9108.         }
  9109.     }
  9110. //        spec.referral_note = spec.referral_note.replace(/\|/g, ' ');
  9111.     
  9112.     if (! spec.rec_type)
  9113.         spec.rec_type = 0;
  9114.  
  9115.     if (spec.comment_level)
  9116.         spec.comment_level = parseInt(spec.comment_level);
  9117.     else
  9118.         spec.comment_level = 0;
  9119.     
  9120.     // Augment with category_name, relationship, language
  9121.     spec.display_url = spec.url;
  9122.     
  9123.     spec.stumblevideo = false;
  9124.     
  9125.     spec.cur_catid = spec.catid;
  9126.     
  9127.     spec.topic_name = su_catnames[spec.catid];
  9128.     if (! spec.topic_name)
  9129.         spec.topic_name = null;
  9130.     
  9131.     spec.cur_topic_name = spec.topic_name;
  9132.     
  9133.     spec.rating = null;
  9134.     
  9135.     var status;
  9136.     // show user's comment (if it's not a referral, and there is a comment) using display_message
  9137.     switch (spec.cluster_type)
  9138.     {
  9139.         case 1:   status = "friend"; break;
  9140.         case 3:   
  9141.             if (spec.firstrater_nick && su_is_mutual_friend(spec.firstrater_nick)) 
  9142.                 status = "friend-sponsored";
  9143.             else
  9144.                 status = "sponsored";
  9145.             break;
  9146.         case 4:
  9147.             status = "referral";
  9148.             spec.rating = su_get_rating(spec.url, false, null);
  9149.             break;
  9150.         default:  status = "firstrater"; break;
  9151.     }
  9152.     spec.relationship = status;
  9153.     
  9154.     spec.language = su_ds.lookup("lang_code:language", spec.lang_code);
  9155.     
  9156.     if (spec.catid2)
  9157.         spec.catid2 = parseInt(spec.catid2);
  9158.  
  9159.     if (spec.catid3)
  9160.         spec.catid3 = parseInt(spec.catid3);
  9161.     
  9162.     spec.eval_interval = 0;
  9163.     
  9164.     spec.shown_dateobj = null;
  9165.     
  9166.     return spec;
  9167. }
  9168.  
  9169. function stumble_done(unseen, context)
  9170. {
  9171.     try {
  9172.     
  9173.     su_stumble_async_context = null;
  9174.     su_get_element("su_stumble").image="chrome://stumbleupon/content/skin/stumble.png";
  9175.  
  9176.     // ignore excessively delayed responses
  9177.     var delay_ms = ((new Date()).getTime()) - context.timestamp;
  9178.     if (delay_ms > su_ds.getValue("@stumble_action_timeout_ms"))
  9179.         return;
  9180.     
  9181.     if ((unseen == "error") || (unseen == "connection error"))
  9182.         return;
  9183.     
  9184.     if (unseen == "")
  9185.     {
  9186.         su_stumble_done_no_stumbles(context);
  9187.         return;
  9188.     }
  9189.     
  9190.     // Build the url_detail spec.
  9191.     
  9192.     var url_detail = su_deserialize_url_command_params(unseen, false);
  9193.     
  9194. //    url_detail.url = "http://media.tumblr.com/mlsyKxOF8fzc9kd1zQ37q9b8o1_500.jpg";
  9195. //    url_detail.urlid = "25624734";
  9196. //    url_detail.tld = su_get_tld(url_detail.url);
  9197.     
  9198.     if (! url_detail)
  9199.     {
  9200.         su_log_error("STUMBLE DESERIALIZE", unseen);
  9201.         clear_stumbles();
  9202.         su_stumble_done_no_stumbles(context);
  9203.         return;
  9204.     }
  9205.     
  9206.     // These shouldn't be served, but it doesn't hurt to do a sanity
  9207.     // check.
  9208.     if ((url_detail.cluster_type != 4) && su_is_domain_blocked(url_detail.tld))
  9209.     {
  9210.         su_enqueue_stumblestats(url_detail);
  9211.         su_load_stumbles(url_detail.url);
  9212.         su_save_stumbles();
  9213.         setTimeout(su_skip_stumble, 0, context);
  9214.         return;
  9215.     }
  9216.     
  9217. //    su_dd("setstumbled", 1, url_detail.url);
  9218.     // Set globals.
  9219.     stumbled_url = url_detail.url;
  9220.     su_redirect_url = url_detail.url;
  9221. //    su_dd("reset", 1);
  9222.     stumbled_redirect = "";
  9223.  
  9224.     // Record url details.
  9225.     su_ds.define("url:url_detail", stumbled_url, url_detail);
  9226.     
  9227. //        if (url_detail.affiliate_url)
  9228. //        {
  9229. //            su_prefetch_url(
  9230. //                        url_detail.affiliate_url,
  9231. //                        su_base_url + "refer.php?url=" + escape(url_detail.affiliate_url),
  9232. //                        0);
  9233. //        }
  9234.     
  9235.     // Show the stumble!
  9236.     shown = su_stumble_done_show_stumble(url_detail, context);
  9237.     
  9238.     if (! shown)
  9239.     {
  9240.         su_check_progress_listener();
  9241.         return;
  9242.     }
  9243.     
  9244.     // Note that we still try to keep the count on the client, and just let the server 
  9245.     // override it with SSC after the submission occurs, if necessary.  We are doing this primarily
  9246.     // for testing purposes because the toolbar might be pointed at a server that doesn't yet 
  9247.     // implement SSC and SFC
  9248.     var stumble_count = su_ds.incrementValue("$stumble_count");
  9249.     su_stumble_count_changed();
  9250.     
  9251.     su_enqueue_stumblestats(url_detail);
  9252.     su_log_dd_uc(unseen);
  9253.     
  9254.     if (context.user_cat.indexOf("TAG_") == 0)
  9255.     {
  9256.         var str = context.user_cat.substr(4).toLowerCase();
  9257.         if (su_ds.isThruDomain(str))
  9258.         {
  9259.             var spec = su_ds.getValue("#recent_info_spec");
  9260.             
  9261.             if (spec.domain && spec.domain == str)
  9262.             {
  9263.                 if (! su_ds.getValue("$shown_toall_info"))
  9264.                     setTimeout(su_display_info, 0, "thru_domain_praise_toall", spec.domain);
  9265.                 else if (! su_ds.getValue("$shown_tomore_info")) 
  9266.                     setTimeout(su_display_info, 0, "thru_domain_praise_tomore", spec.domain);
  9267.             }
  9268.             
  9269.             su_close_info();
  9270.         }
  9271.     }
  9272.     else if (context.user_cat == "302")
  9273.     {
  9274.         su_ds.setValue("$shown_photo_info", true);
  9275.         
  9276.         var spec = su_ds.getValue("#recent_info_spec");
  9277.         
  9278.         
  9279.         if ((spec.type == "photo") && (! su_ds.getValue("$shown_toall_info")))
  9280.             setTimeout(su_display_info, 0, "photo_praise");
  9281.         
  9282.         su_close_info();
  9283.     }
  9284.     else if (su_is_image_url(url_detail.url) && (! su_ds.getValue("$shown_photo_info")))
  9285.     {
  9286.         setTimeout(su_display_info, 0, "photo");
  9287.         
  9288.         su_close_info();
  9289.     }
  9290.     else
  9291.     {
  9292.         su_close_info();
  9293.     }
  9294.     
  9295.     // Remove the url from our local stumble queue.
  9296.     //!!! We want to do
  9297.     //    - removal from local queue
  9298.     //    - stumbletimes recording
  9299.     //    - referral count decriment
  9300.     //    after both (a) the page loads enough for the user to have
  9301.     //    reviewed content and (b) the user has visited the tab.  But
  9302.     //    detecting those events is a relatively difficult problem. 
  9303.     //    -- JW
  9304.     
  9305.     //!!! Are we removing multiple referrals for the same url? -- JW
  9306.     su_load_stumbles(url_detail.url);
  9307.     su_save_stumbles();
  9308.     
  9309.     // Update topic UI elements.
  9310.     su_update_topic_and_reporting(url_detail, url_detail, url_detail.tld, true, null);
  9311. //    su_update_language(url_detail, true);
  9312.     
  9313.     // Clear old sponsor or firstrater buttons
  9314. //    su_set_visible("su_sponsor", false);
  9315. //    su_set_visible("firstrater", false);
  9316.  
  9317.     // If we have a message, display it.
  9318.     if (url_detail.is_friend_referral || url_detail.referral_note)
  9319.     {
  9320.         setTimeout(
  9321.                     su_stumble_done_display_message,
  9322.                     0,
  9323.                     url_detail,
  9324.                     context.target_browser);
  9325.     }
  9326.     else if ((stumble_count >= 5) &&
  9327.             ((su_ds.getValue("$thumbup_count") + su_ds.getValue("$thumbdown_count")) <= 1) &&
  9328.             (! su_ds.getValue("$shown_rate_info")))
  9329.     {
  9330.         su_display_info("rate");
  9331.     }
  9332.     
  9333.     // If this is a referral, decriment referral count.
  9334.     //!!! May get out of sync if we start sending referrals via the SV 
  9335.     //    page. -- JW
  9336.     if (url_detail.cluster_type == 4)
  9337.         su_decriment_undelivered_count();
  9338.     
  9339.     
  9340.     if ((! context.stumblevideo) && 
  9341.                 (stumbled_url.indexOf(su_serverhttp + "first_stumble.php") != 0))
  9342.     {
  9343.         // get unseen url, but don't hit the server to do it
  9344.         su_get_unseen_url(
  9345.                     context.user_cat,
  9346.                     0,
  9347.                     null,
  9348.                     null);
  9349.     }
  9350.     
  9351.     su_check_progress_listener();
  9352.     
  9353.     su_register_activity("stumble");
  9354.     
  9355.     } catch (e) { su_log_error("STUMBLE DONE", e); }
  9356. }
  9357.  
  9358. function su_is_image_url(url)
  9359. {
  9360.     //!!! Ideally, we should use the content type logic from the
  9361.     // surveyor. -- JW
  9362.     return (url.match(/\.(jpg|jpeg|png|gif)$/) ? true : false);
  9363. }
  9364.  
  9365. function su_stumble_done_show_stumble(url_detail, context)
  9366. {
  9367.     try {
  9368.         su_prefetcher.advancePastTarget(stumbled_url);
  9369.     } catch (e) { su_log_error("PREFETCHER 5", e); }
  9370.     
  9371.     var detail = su_get_async_target_browser(
  9372.                 context.target_browser,
  9373.                 context.new_tab);
  9374.     
  9375.     if (! detail)
  9376.         return false;
  9377.     
  9378.     context.target_browser = detail.target_browser;
  9379.     
  9380.     if (context.target_browser.su_url_detail && context.target_browser.su_url_detail.messageid)
  9381.     {
  9382.         setTimeout(
  9383.                 su_close_message,
  9384.                 0,
  9385.                 context.target_browser.su_url_detail.messageid,
  9386.                 true);
  9387.     }
  9388.     
  9389.     context.target_browser.su_url_detail = url_detail;
  9390.     
  9391.     //var referrer = su_base_url + "refer.html";
  9392.     var referrer = su_base_url + "refer.php?url=" + encodeURIComponent(stumbled_url);
  9393.     if (url_detail.referrer)
  9394.         referrer = url_detail.referrer;
  9395.     
  9396.     if (! su_ds.getValue("@enable_refer"))
  9397.         referrer = "about:blank";
  9398.     
  9399.     if (su_is_adult_category(url_detail.catid))
  9400.         referrer = url_detail.url;
  9401.     
  9402.     var postdata = "";
  9403.     if (url_detail.url.indexOf(su_base_url + "signup.php") == 0)
  9404.         postdata = su_get_client_postdata(url_detail.url);
  9405.     
  9406.     var listener = new su_StumbleProgressListener(url_detail, context);
  9407.     try {
  9408.         context.target_browser.addProgressListener(listener);
  9409.     } catch (e) {}
  9410.     
  9411.     //    context.target_browser.su_content_clicked = false;
  9412.     try {
  9413.         context.target_browser.webNavigation.loadURI(
  9414.                     url_detail.url,
  9415.                     0,
  9416.                     su_get_nsiuri(referrer),
  9417.                     (postdata == "") ? null : su_get_mime_input_stream(postdata, "application/x-www-form-urlencoded"),
  9418.                     null);
  9419.     } catch (e) { su_log_error("LOADURI ERROR4", e, url_detail.url); }
  9420.  
  9421.     return true;
  9422. }
  9423.  
  9424. function su_enqueue_stumblestats(url_detail)
  9425. {
  9426.     if (!url_detail.publicid)
  9427.         return;
  9428.  
  9429.     // Old urlids, don't store, just send
  9430.     var recently_seen = su_ds.getValue("$recently_seen");
  9431.     var seen_urlids;
  9432.     if (recently_seen == "")
  9433.         seen_urlids = new Array();
  9434.     else
  9435.         seen_urlids = recently_seen.split(".");
  9436.     
  9437.     // New format, public ids
  9438.     var recently_seen_publicids = su_ds.getValue("$recently_seen_publicids");
  9439.     var seen_publicids;
  9440.     if(recently_seen_publicids == "")
  9441.         seen_publicids = new Array();
  9442.     else
  9443.         seen_publicids = recently_seen_publicids.split(".");
  9444.  
  9445.     // Add this public id to recentlyseen
  9446.     seen_publicids.push(url_detail.publicid);
  9447.     while (seen_publicids.length > 50)
  9448.         seen_publicids.shift();
  9449.     su_ds.setValue("$recently_seen_publicids", seen_publicids.join("."));
  9450.     
  9451.     // Recently seen referral ids
  9452.     var recently_seen_referralids = su_ds.getValue("$recently_seen_referralids");
  9453.     var seen_referralids;
  9454.     if(recently_seen_referralids == "")
  9455.         seen_referralids = new Array();
  9456.     else
  9457.         seen_referralids = recently_seen_referralids.split(".");
  9458.     
  9459.     // Add this referral id to recentlyseen referralids
  9460.     seen_referralids.push(url_detail.referralid);
  9461.     while (seen_referralids.length > 50)
  9462.         seen_referralids.shift();
  9463.     su_ds.setValue("$recently_seen_referralids", seen_referralids.join("."));
  9464.     
  9465.     su_ds.flushPrefs();
  9466.  
  9467.     // Add the visited URL details to the visited table
  9468.     su_stumbleReporter.addVisitedUrl(url_detail);
  9469. }
  9470.  
  9471. function su_get_async_target_browser(target_browser, new_tab)
  9472. {
  9473.     var detail = new Object();
  9474.     
  9475.     var browser = getBrowser();
  9476.     
  9477.     if (new_tab)
  9478.     {
  9479.         var characterSet = browser.contentDocument.characterSet;
  9480.         try {
  9481.             var tab = browser.addTab(
  9482.                         "about:blank",
  9483.                         stumbled_url,
  9484.                         null,
  9485.                         characterSet);
  9486.             detail.target_browser = browser.getBrowserForTab(tab);
  9487.             browser.selectedTab = tab;
  9488.         } catch (e) { su_log_error("ADDTAB ERROR", e, stumbled_url); }
  9489.     }
  9490.     else
  9491.     {
  9492.         var found = false;
  9493.         for (var i = 0; i < browser.browsers.length; i++)
  9494.         {                                                         
  9495.             if (browser.browsers[i] == target_browser)
  9496.             {
  9497.                 detail.target_browser = target_browser;
  9498.                 found = true;
  9499.                 break;
  9500.             }
  9501.         }
  9502.         
  9503.         if (! found)
  9504.         {
  9505.             // Cancel the stumble if, by the time we get here, 
  9506.             // they've closed the tab. -- JW
  9507.             detail = null;
  9508.         }
  9509.     }
  9510.     return detail;
  9511. }
  9512.  
  9513. function su_decriment_undelivered_count()
  9514. {
  9515.     // decriment referral count
  9516.     var count = su_ds.getValue("$undelivered_count");
  9517.     count--;
  9518.     su_ds.setValue("$undelivered_count", count);
  9519.     
  9520.     su_update_referred(true);
  9521.  
  9522.     setTimeout(su_test, 1000);
  9523. }
  9524.  
  9525. function su_test()
  9526. {
  9527. }
  9528.  
  9529. function su_stumble_done_no_stumbles(context)
  9530. {
  9531.     var user_cat = context.user_cat + "";
  9532.  
  9533.     var detail = su_get_async_target_browser(
  9534.                 context.target_browser,
  9535.                 context.new_tab);
  9536.     
  9537.     if (! detail)
  9538.         return;
  9539.     
  9540.     var target_browser = detail.target_browser;
  9541.     
  9542.     var target_url;
  9543.     // We couldn't find an unseen url...
  9544.     // Check to make sure this isn't an incat stumble
  9545.     if (user_cat == "0")
  9546.     {
  9547.         // If we got here, we're out of urls, and we're in "Any Topic"
  9548.         //!!! first make sure we are not already here....
  9549.         target_url = su_base_url + "interests.php?out=1"; 
  9550.         
  9551.         target_browser.webNavigation.loadURI(
  9552.                     target_url,
  9553.                     0,
  9554.                     null,
  9555.                     su_get_mime_input_stream(
  9556.                         su_get_client_postdata(target_url),
  9557.                         "application/x-www-form-urlencoded"),
  9558.                     null);
  9559.  
  9560.         // change icon...
  9561.         su_get_element("su_stumble").image = "chrome://stumbleupon/content/skin/stumble.png";
  9562.  
  9563.         return;
  9564.         //!!! eventually we should cycle through "great history" here
  9565.     }
  9566.     
  9567.     var tag = "";
  9568.     var mode = "";
  9569.     var profile = "";
  9570.     if (su_isInt(user_cat))
  9571.     {
  9572.         // mode = incat
  9573.         mode = "incat";
  9574.         su_load_categories();
  9575.         if (typeof(su_catnames[user_cat]) != "undefined")
  9576.             tag = su_catnames[user_cat];
  9577.         else
  9578.             tag = "";
  9579.     }
  9580.     else if (user_cat.indexOf("LANG_") == 0)
  9581.     {
  9582.         mode = "language";
  9583.         tag = su_ds.lookup("lang_code:language", user_cat.substr(5));
  9584.     } 
  9585.     else if (user_cat.indexOf("TAG_") == 0)
  9586.     {
  9587.         mode = "tag";
  9588.         tag = user_cat.substr(4);
  9589.     }
  9590.     else if (user_cat.indexOf("USERTAG_") == 0)
  9591.     {
  9592.         mode = "showfriendtag";
  9593.         var chunk = user_cat.substr(8);
  9594.         chunks = chunk.split('_');
  9595.         var tag = chunks[1];
  9596.         var profile = chunks[0];
  9597. //                alert("tag " + tag + " profile " + profile);
  9598.     }
  9599.     else
  9600.     {
  9601.         if (user_cat == "news")
  9602.         {
  9603.             mode = "news";    
  9604.             tag = "news";
  9605.         }
  9606.         else if (user_cat == "video")
  9607.         {
  9608.             mode = "video";    
  9609.             tag = "video";
  9610.         }
  9611.         else if (user_cat == "friends")
  9612.         {
  9613.             mode = "friends";    
  9614.             tag = "friends";
  9615.         }
  9616.         else if (user_cat == "wiki")
  9617.         {
  9618.             mode = "wiki";
  9619.             tag = "wiki";
  9620.         }
  9621.         else
  9622.         {
  9623.             mode = "showfriend";    
  9624.             profile = user_cat;
  9625.         }
  9626.     }    
  9627.     
  9628.     target_url = su_base_url + "explore.php?mode=" + mode;
  9629.     if (tag != "")
  9630.         target_url += "&tag=" + tag.toLowerCase();
  9631.     if (profile != "")
  9632.         target_url += "&showfriend=" + profile.toLowerCase();
  9633.     if (mode == "incat")
  9634.         target_url += "&topic=" + user_cat;
  9635.         
  9636.     // User is doing an incat stumble
  9637.     // Set user_cat to 0
  9638.     su_set_mode_all();
  9639.     // Give them a message explaining they have run out in their particular cat.
  9640.  
  9641.     // grab the current HTML window
  9642.         
  9643.     target_browser.webNavigation.loadURI(
  9644.                 target_url,
  9645.                 0,
  9646.                 null,
  9647.                 su_get_mime_input_stream(
  9648.                     su_get_client_postdata(target_url),
  9649.                     "application/x-www-form-urlencoded"),
  9650.                 null);
  9651.  
  9652.     // change icon...
  9653.     su_get_element("su_stumble").image = "chrome://stumbleupon/content/skin/stumble.png";
  9654. }
  9655.  
  9656.  
  9657.  
  9658. // used by a timeout to ensure that the stumble button icon returns
  9659. // to vertical within 15 seconds
  9660. function su_reset_stumble_action_indicator(stumble_action_id)
  9661. {
  9662.     if (stumble_action_id == su_stumble_action_count)
  9663.         su_get_element("su_stumble").image="chrome://stumbleupon/content/skin/stumble.png";
  9664. }
  9665.  
  9666. // used load_data2
  9667. function su_check_referral(force_update)
  9668. {
  9669.     if (stumbleid == 0)
  9670.         return;
  9671.     
  9672.     var check_now = force_update;
  9673.  
  9674.     if (su_check_referral_timer)
  9675.     {
  9676.         // if the user changes, this clears the timeout set for the
  9677.         // previously logged in user
  9678.         clearTimeout(su_check_referral_timer);
  9679.     }
  9680.     
  9681.     var state = su_ds.getValue("$poll_state");
  9682.     var interval = su_ds.lookup("state:poll_interval_s", state);
  9683.     var poll_time_s = su_ds.getIntValue("$poll_time_s");
  9684.     var now_s = su_get_time_s();
  9685.     var elapsed = now_s - poll_time_s;
  9686.     if (elapsed >= interval)
  9687.         check_now = true;
  9688.     
  9689.     if (check_now)
  9690.     {
  9691.         elapsed = 0;
  9692.         // advance state
  9693.         var new_state = null;
  9694.         switch (state)
  9695.         {
  9696.             case "b": new_state = "c"; break;
  9697.             case "c": new_state = "d"; break;
  9698.             case "d": new_state = "e"; break;
  9699.             case "e": new_state = "f"; break;
  9700.             case "a":
  9701.             case "f":
  9702.             case "g":
  9703.                 var activity_time_s = su_ds.getIntValue("$activity_time_s");
  9704.                 if (activity_time_s == 0)
  9705.                     activity_time_s = now_s;
  9706.                 
  9707.                 var idle_interval = now_s - activity_time_s;
  9708.                 if (idle_interval > (3600 * 24 * 60))
  9709.                     new_state = "h";
  9710.                 else if (idle_interval > (3600 * 24 * 10))
  9711.                     new_state = "g";
  9712.                 break;
  9713.         }
  9714.         
  9715.         if (new_state)
  9716.         {
  9717.             su_ds.setValue("$poll_state", new_state);
  9718.             interval = su_ds.lookup("state:poll_interval_s", new_state);
  9719.         }
  9720.         
  9721.         su_ds.setValue("$poll_time_s", now_s);
  9722.         
  9723.         var context = new su_AsyncContext();
  9724.         context.quiet = true;
  9725.         context.user_cat = 0;
  9726.         
  9727.         su_update_url_cache(
  9728.                     0,
  9729.                     true, // check_referral
  9730.                     su_check_referral_done,
  9731.                     context);
  9732.     }
  9733.     
  9734.     su_check_referral_timer = setTimeout(su_check_referral, ((interval - elapsed) * 1000), false);
  9735. }
  9736.  
  9737. function su_register_activity(type)
  9738. {
  9739.     if (stumbleid == 0)
  9740.         return;
  9741.     
  9742.     su_ds.setValue("$activity_time_s", su_get_time_s());
  9743.     
  9744.     var state = su_ds.getValue("$poll_state");
  9745.     var new_state = state;
  9746.     switch (type)
  9747.     {
  9748.         case "referred":
  9749.             if (state == "a" || state == "g" || state == "h")
  9750.                 new_state = "f";
  9751.             break;
  9752.         case "referral":
  9753.             if (state == "a" || state == "d" || state == "e" || state == "g" || state == "h")
  9754.                 new_state = "b";
  9755.             break;
  9756.         case "stumble":
  9757.         case "rate":
  9758.         case "message-notify":
  9759.             if (state == "g" || state == "h")
  9760.                 new_state = "a";
  9761.             break;
  9762.     }
  9763.     
  9764.     if (new_state != state)
  9765.     {
  9766.         su_ds.setValue("$poll_state", new_state);
  9767.         su_check_referral(false);
  9768.     }
  9769. }
  9770.  
  9771. function su_check_referral_done(error)
  9772. {
  9773.     if (error == "connection error")
  9774.         setTimeout(su_check_referral_retry, 10000);
  9775. }
  9776.  
  9777. function su_check_referral_retry()
  9778. {
  9779.     // Retry once.  This mostly caters to DSL users who have to wait
  9780.     // for the modem to reconnect. -- JW
  9781.     var context = new su_AsyncContext();
  9782.     context.quiet = true;
  9783.     context.user_cat = 0;
  9784.     
  9785.     su_update_url_cache(
  9786.                 0,
  9787.                 true, // check_referral
  9788.                 null,
  9789.                 context);
  9790. }
  9791.  
  9792. function su_show_searchlinks_dialog(new_user_prompt, new_tab, stumble)
  9793. {
  9794.     var intro_count = su_ds.getValue("$intro_count");
  9795.     if ((intro_count == 0) || ((intro_count % 15) != 0)) return false;
  9796.     if (su_ds.getValue("$shown_searchlinks_dialog")) return false;
  9797.     su_ds.setValue("$shown_searchlinks_dialog", true);
  9798.     if (su_ds.getValue("$show_searchlinks_score")) return false;
  9799.     if (su_ds.getValue("$show_searchlinks_friends")) return false;
  9800.     if (su_ds.getValue("$show_searchlinks_topic")) return false;
  9801.     window.setTimeout(su_show_searchlinks_dialog_wrapped, 100, new_user_prompt, new_tab, stumble);
  9802.     return true;
  9803. }
  9804.  
  9805. function su_show_searchlinks_dialog_wrapped(new_user_mode, new_tab, stumble)
  9806. {
  9807.     var detail = new Object();
  9808.     var filename;
  9809.     var social = su_ds.hasFeature("$sociallinks");
  9810.     if (social && new_user_mode)
  9811.         filename = "social_searchlinks_newuser_prompt.gif";
  9812.     else if (social)
  9813.         filename = "social_searchlinks_prompt.gif";
  9814.     else if (new_user_mode)
  9815.         filename = "searchlinks_newuser_prompt.gif";
  9816.     else
  9817.         filename = "searchlinks_prompt.gif";
  9818.     
  9819.     if (new_user_mode)
  9820.         detail.preview_serp_url = "http://www.google.com/search?q=StumbleUpon";
  9821.     else
  9822.         detail.preview_serp_url = null;
  9823.     detail.new_tab = new_tab;
  9824.     detail.prompt_filename = filename;
  9825.     detail.stumble = stumble;
  9826.     
  9827.     su_ds.installResource(
  9828.                 "http://cdn.stumble-upon.com/images/" + filename,
  9829.                 "images",
  9830.                 filename);
  9831.     
  9832.     su_searchlinks_dialog_detail = detail;
  9833. }
  9834.  
  9835. function su_handle_searchlinks_dialog_resource_load(detail)
  9836. {
  9837.     detail.prompt_src = su_ds.getResourceURLFromName(
  9838.                 "images",
  9839.                 detail.prompt_filename);
  9840.  
  9841.     window.openDialog(
  9842.                 "chrome://stumbleupon/content/searchlinksDialog.xul",
  9843.                 "",
  9844.                 "chrome,dialog,centerscreen,dependent,close=no",
  9845.                 detail);
  9846. }
  9847.  
  9848. function su_handle_searchlinks_dialog_close(detail)
  9849. {
  9850.     if (detail.result == "cancel-error")
  9851.     {
  9852.         detail.result = "";
  9853.     
  9854.         window.openDialog(
  9855.                     "chrome://stumbleupon/content/searchlinksDialog.xul",
  9856.                     "",
  9857.                     "chrome,dialog,centerscreen,dependent,close=no",
  9858.                     detail);
  9859.     }
  9860.     else if (detail.result == "yes")
  9861.     {
  9862.         su_ds.setValue("$show_searchlinks_score", true);
  9863.         su_ds.setValue("$show_searchlinks_friends", true);
  9864.         su_ds.setValue("$shown_searchlinks", true);
  9865.         su_ds.flushPrefs();
  9866.         
  9867.         if (detail.preview_serp_url)
  9868.         {
  9869.             // The timeout and the su_ds.flushPrefs() above work around an 
  9870.             // intermittent timing issue where the link behavior isn't
  9871.             // enabled in time for searchlinks to appear in the demo. -- JW
  9872.             setTimeout(
  9873.                         su_set_location,
  9874.                         150,
  9875.                         detail.preview_serp_url,
  9876.                         null, 
  9877.                         detail.new_tab);
  9878.         }
  9879.     }
  9880.     else
  9881.     {
  9882.         su_ds.setValue("$show_searchlinks_score", false);
  9883.         su_ds.setValue("$show_searchlinks_friends", false);
  9884.         su_ds.setValue("$show_searchlinks_topic", false);
  9885.     }
  9886. }
  9887.  
  9888. function su_check_show_position_dialog()
  9889. {
  9890.     if(su_ds.getValue("$shown_position_dialog")) return false;
  9891.     su_ds.setValue("$shown_position_dialog", true);
  9892.     if(su_ds.getValue("@toolbar-position") != su_ds.getDefaultValue("@toolbar-position")) return false;
  9893.     if(su_ds.getValue("$stumble_count") < 5) return false;
  9894.  
  9895.     var detail = new Object();
  9896.     window.openDialog(
  9897.                 "chrome://stumbleupon/content/positionDialog.xul",
  9898.                 "",
  9899.                 "chrome,dialog,centerscreen,dependent,close=no",
  9900.                 detail);
  9901.     return true;
  9902. }
  9903.  
  9904. function su_handle_position_dialog_close(detail)
  9905. {
  9906.     if (detail.result == "cancel-error")
  9907.     {
  9908.         detail.result = "";
  9909.     
  9910.         window.openDialog(
  9911.                     "chrome://stumbleupon/content/positionDialog.xul",
  9912.                     "",
  9913.                     "chrome,dialog,centerscreen,dependent,close=no",
  9914.                     detail);
  9915.     }
  9916.     else if (detail.result == "yes")
  9917.     {
  9918.         su_move_to_bookmark_bar();
  9919.     }
  9920. }
  9921.  
  9922. function su_stumble_done_display_message(url_detail, target_browser)
  9923. {
  9924.     //!!! test in FF 1.5, Seamonkey, Flock
  9925.     var box = target_browser.parentNode;
  9926.     
  9927.     var messageid = su_ds.incrementValue("~message_count");
  9928.     
  9929.     target_browser.su_url_detail.messageid = messageid;
  9930.     
  9931.     // This stack prevents reflow of the banner content upon show/hide.
  9932.     // We could reuse it, but there's no compelling reason to. -- JW
  9933.     var stack = document.createElement("stack");
  9934.     
  9935.     var outerbox = document.createElement("vbox");
  9936.     var outerbox_id = "su_messageOuterBox" + messageid;
  9937.     outerbox.setAttribute("id", outerbox_id);
  9938.     outerbox.style.position = "fixed";
  9939.     outerbox.style.top = "100%";
  9940.     if (su_host.mac)
  9941.         outerbox.setAttribute("class", "su_pinstripe_bannerBox outset");
  9942.     else
  9943.         outerbox.setAttribute("class", "su_winstripe_bannerBox outset");
  9944.     
  9945.     stack.appendChild(outerbox);
  9946.     
  9947.     var grid = document.createElement("grid");
  9948.     grid.setAttribute("flex", "1");
  9949.     outerbox.appendChild(grid);
  9950.     var columns = document.createElement("columns");
  9951.     grid.appendChild(columns);
  9952.     var el;
  9953.     el = document.createElement("column");
  9954.     columns.appendChild(el);
  9955.     el = document.createElement("column");
  9956.     el.setAttribute("flex", "1");
  9957.     columns.appendChild(el);
  9958.     el = document.createElement("column");
  9959.     columns.appendChild(el);
  9960.     var rows = document.createElement("rows");
  9961.     rows.setAttribute("flex", "1");
  9962.     grid.appendChild(rows);
  9963.     
  9964.     var firstrow = document.createElement("row");
  9965.     if (su_host.mac)
  9966.         firstrow.setAttribute("class", "su_pinstripe_bannerInnerBox");
  9967.     rows.appendChild(firstrow);
  9968.     
  9969.     var hboxaa = document.createElement("hbox");
  9970.     hboxaa.setAttribute("align", "center");
  9971.     firstrow.appendChild(hboxaa);
  9972.     
  9973.     el = document.createElement("image");
  9974.     el.setAttribute("src", su_get_message_icon_src(url_detail));
  9975.     el.setAttribute("class", "su_bannerImage");
  9976.     if (! url_detail.is_system_referral)
  9977.     {
  9978.         el.setAttribute("style", "cursor: pointer;");
  9979.         el.setAttribute("onclick", "su_handle_message_sender_click(event, " + messageid + ")");
  9980.     }
  9981.     hboxaa.appendChild(el);
  9982.     el = document.createElement("label");
  9983.     el.setAttribute("value", url_detail.sender);
  9984.     if (! url_detail.is_system_referral)
  9985.     {
  9986.         el.setAttribute("style", "color: rgb(0,0,238); text-decoration: underline; margin-right:0; cursor: pointer;");
  9987.         el.setAttribute("onclick", "su_handle_message_sender_click(event, " + messageid + ")");
  9988.     }
  9989.     hboxaa.appendChild(el);
  9990.     el = document.createElement("label");
  9991.     el.setAttribute("style", "margin-left: 0");
  9992.     el.setAttribute("value", su_get_message_label(url_detail));
  9993.     hboxaa.appendChild(el);
  9994.  
  9995.     var hboxab = document.createElement("hbox");
  9996.     hboxab.setAttribute("flex", "1");
  9997.     hboxab.setAttribute("align", "center");
  9998.     firstrow.appendChild(hboxab);
  9999.  
  10000.     messagedeck = document.createElement("deck");
  10001.     messagedeck.setAttribute("flex", "1");
  10002.     messagedeck.setAttribute("align", "center");
  10003.     hboxab.appendChild(messagedeck);
  10004.     
  10005.     el = document.createElement("textbox");
  10006.     el.setAttribute("id", "su_bannerLineTextbox" + messageid);
  10007.     el.setAttribute("multiline", "false");
  10008.     el.setAttribute("value", "");
  10009.     el.setAttribute("readonly", "true");
  10010.     el.setAttribute("hidden", "true");
  10011.     if (su_host.mac)
  10012.         el.setAttribute("class", "su_pinstripe_bannerMessage");
  10013.     else
  10014.         el.setAttribute("class", "su_winstripe_bannerMessage");
  10015.     messagedeck.appendChild(el);
  10016.     
  10017.     el = document.createElement("textbox");
  10018.     el.setAttribute("id", "su_bannerMultilineTextbox" + messageid);
  10019.     el.setAttribute("multiline", "true");
  10020.     el.setAttribute("value", "");
  10021.     el.setAttribute("readonly", "true");
  10022.     el.setAttribute("hidden", "true");
  10023.     if (su_host.mac)
  10024.         el.setAttribute("class", "su_pinstripe_bannerMessage");
  10025.     else
  10026.         el.setAttribute("class", "su_winstripe_bannerMessage");
  10027.     messagedeck.appendChild(el);
  10028.  
  10029.     el = document.createElement("description");
  10030.     el.setAttribute("id", "su_bannerTextMeasurer" + messageid);
  10031.     el.setAttribute("flex", "1");
  10032.     el.setAttribute("crop", "end");
  10033.     el.setAttribute("style", "margin-left: 8px; margin-right: 8px;");
  10034.     messagedeck.appendChild(el);
  10035.  
  10036.     if (url_detail.is_friend_referral)
  10037.     {
  10038.         el = document.createElement("button");
  10039.         el.setAttribute("id", "su_bannerReplyButton" + messageid);
  10040.         el.setAttribute("label", "Reply Now");
  10041.         el.setAttribute("accesskey", "R");
  10042.         el.setAttribute("oncommand", "su_handle_message_reply_command(" + messageid + ")");
  10043.         hboxab.appendChild(el);
  10044.     }
  10045.     el = document.createElement("spacer");
  10046.     el.setAttribute("flex", "1000");
  10047.     hboxab.appendChild(el);
  10048.     
  10049.     el = document.createElement("button");
  10050.     el.setAttribute("id", "su_bannerReloadButton" + messageid);
  10051.     if (url_detail.is_friend_referral || url_detail.is_system_referral)
  10052.         el.setAttribute("label", "Reload Sent Page");
  10053.     else
  10054.         el.setAttribute("label", "Reload Stumbled Page");
  10055.     el.setAttribute("accesskey", "L");
  10056.     el.setAttribute("disabled", "true");
  10057.     el.setAttribute("oncommand", "su_handle_message_reload_command(" + messageid + ")");
  10058.     hboxab.appendChild(el);
  10059.  
  10060.     var elac = document.createElement("toolbarbutton");
  10061.     if (su_host.mac)
  10062.         elac.setAttribute("class", "su_pinstripe_messageCloseButton");
  10063.     else
  10064.         elac.setAttribute("class", "su_winstripe_messageCloseButton");
  10065.     elac.setAttribute("oncommand", "su_handle_message_close_command(" + messageid + ")");
  10066.     firstrow.appendChild(elac);
  10067.     
  10068.     var secondrow = document.createElement("row");
  10069.     secondrow.setAttribute("id", "su_messageSendRow" + messageid); 
  10070.     secondrow.setAttribute("hidden", "true");
  10071.     rows.appendChild(secondrow);
  10072.     
  10073.     var hboxba = document.createElement("hbox");
  10074.     hboxba.setAttribute("pack", "end");
  10075.     hboxba.setAttribute("align", "center");
  10076.     secondrow.appendChild(hboxba);
  10077.     
  10078.     el = document.createElement("label");
  10079.     el.setAttribute("value", "Reply:");
  10080.     hboxba.appendChild(el);
  10081.     
  10082.     var hboxbb = document.createElement("hbox");
  10083.     hboxbb.setAttribute("flex", "1");
  10084.     secondrow.appendChild(hboxbb);
  10085.     
  10086.     el = document.createElement("textbox");
  10087.     el.setAttribute("flex", "1");
  10088.     el.setAttribute("id", "su_messageTextbox" + messageid);
  10089.     el.setAttribute("class", "su_messageTextbox");
  10090.     el.setAttribute("maxlength", 5000);
  10091.     el.setAttribute("onkeypress", "su_handle_message_keypress(event, " + messageid + ")");
  10092.     hboxbb.appendChild(el);
  10093.     el = document.createElement("button");
  10094.     el.setAttribute("label", "Send");
  10095.     el.setAttribute("accesskey", "S");
  10096.     el.setAttribute("oncommand", "su_handle_message_send_command(" + messageid + ")");
  10097.     hboxbb.appendChild(el);
  10098.     el = document.createElement("button");
  10099.     el.setAttribute("label", "Cancel");
  10100.     el.setAttribute("accesskey", "C");
  10101.     el.setAttribute("oncommand", "su_handle_message_cancel_command(" + messageid + ")");
  10102.     hboxbb.appendChild(el);
  10103.     
  10104.     box.insertBefore(stack, target_browser);
  10105.     
  10106.     if (url_detail.referral_note)
  10107.     {
  10108.         var measurer = su_get_element("su_bannerTextMeasurer" + messageid);
  10109.         measurer.textContent = url_detail.referral_note + "  ";
  10110.  
  10111.         su_set_drawer_open(
  10112.             outerbox_id,
  10113.             true,
  10114.             su_init_message_textbox,
  10115.             messageid);
  10116.     }
  10117.     else
  10118.     {
  10119.         su_set_drawer_open(outerbox_id, true, null);
  10120.     }
  10121. }
  10122.  
  10123. function su_init_message_textbox(messageid)
  10124. {
  10125.     var target_browser = null;
  10126.     var browsers = getBrowser().browsers;
  10127.     for (i = 0; i < browsers.length; i++)
  10128.     {
  10129.         if (browsers[i].su_url_detail && browsers[i].su_url_detail.messageid &&
  10130.                     (browsers[i].su_url_detail.messageid == messageid))
  10131.         {
  10132.             target_browser = browsers[i];
  10133.             break;
  10134.         }
  10135.     }
  10136.     
  10137.     var measurer = target_browser.ownerDocument.getElementById("su_bannerTextMeasurer" + messageid);
  10138.     var height = measurer.boxObject.height; 
  10139.     var line_count = Math.round(height / 17);
  10140.     if (line_count > 1)
  10141.     {
  10142.         target_browser.ownerDocument.getElementById("su_bannerLineTextbox" + messageid).hidden = true;
  10143.         var textbox = target_browser.ownerDocument.getElementById("su_bannerMultilineTextbox" + messageid);
  10144.         textbox.setAttribute("rows", line_count - 1);
  10145.         textbox.setAttribute("height", (height + 5) + "px");
  10146.         textbox.value = target_browser.su_url_detail.referral_note;
  10147.         textbox.hidden = false;
  10148.     }
  10149.     else
  10150.     {
  10151.         var width = measurer.boxObject.width;
  10152.         var textbox = target_browser.ownerDocument.getElementById("su_bannerLineTextbox" + messageid);
  10153.         textbox.setAttribute("width", (width + 10) + "px");
  10154.         textbox.value = target_browser.su_url_detail.referral_note;
  10155.         textbox.hidden = false;
  10156.     }
  10157. }
  10158.  
  10159. function su_get_message_icon_src(url_detail)
  10160. {
  10161.     var src;
  10162.     if (url_detail.is_friend_referral)
  10163.     {
  10164.         var contact = su_ds.selectRow("contact", "nickname", url_detail.sender);
  10165.         if (! contact)
  10166.             contact = su_ds.selectRow("contact", "contactid", url_detail.sender);
  10167.         
  10168.         if (contact && contact.contactid)
  10169.         {
  10170.             var filename = contact.contactid + ".jpg";
  10171.             
  10172.             if (su_ds.isResourceInstalled("iconpics", filename))
  10173.                 src = su_ds.getResourceURLFromName("iconpics", filename);
  10174.             else
  10175.                 src = "http://cdn.stumble-upon.com/iconpics/" + filename;
  10176.             
  10177.             su_ds.refreshAvatar(contact.contactid);
  10178.         }
  10179.         else
  10180.         {
  10181.             src = "chrome://stumbleupon/content/skin/arrow.png";
  10182.         }
  10183.     }
  10184.     else if (url_detail.is_system_referral)
  10185.     {
  10186.         src = "chrome://stumbleupon/content/skin/arrow.png";
  10187.     }
  10188.     else
  10189.     {
  10190.         src = "chrome://stumbleupon/content/skin/bubble3.png";
  10191.     }
  10192.     return src;
  10193. }    
  10194.  
  10195. function su_get_message_label(url_detail)
  10196. {
  10197.     var label = "";
  10198.     if (url_detail.is_friend_referral || url_detail.is_system_referral)
  10199.     {
  10200.         if (url_detail.referral_note)
  10201.             label += " says:"; 
  10202.         else
  10203.             label += " sent you this page";
  10204.     }
  10205.     else if (url_detail.referral_note)
  10206.     {
  10207.         label += " reviewed saying:";
  10208.     }
  10209.     
  10210.     return label;
  10211. }
  10212.  
  10213. function su_handle_message_sender_click(event, messageid)
  10214. {
  10215.     var url_detail = su_get_message_url_detail(messageid);
  10216.     var new_tab = true;
  10217.     if (su_ds.getValue("$sender_click_platform"))
  10218.         new_tab = su_new_tab(event);
  10219.     su_set_location(
  10220.                 "http://" + url_detail.sender + "." + su_servername + "/",
  10221.                 null,
  10222.                 new_tab);
  10223. }
  10224.  
  10225. function su_handle_message_keypress(event, messageid)
  10226. {
  10227.     if (event.keyCode != KeyEvent.DOM_VK_RETURN)
  10228.         return;
  10229.     
  10230.     su_send_reply_message(messageid);
  10231. }
  10232.  
  10233. function su_handle_message_reply_command(messageid)
  10234. {
  10235.     su_get_element("su_bannerReplyButton" + messageid).disabled = true;    
  10236.     su_get_element("su_messageSendRow" + messageid).hidden = false;
  10237.     setTimeout(
  10238.                 function (messageid) {
  10239.                     su_get_element("su_messageTextbox" + messageid).focus(); },
  10240.                 0,
  10241.                 messageid);
  10242. }
  10243.  
  10244. function su_handle_message_reload_command(messageid)
  10245. {
  10246.     var browser = su_get_message_browser(messageid);
  10247.     var url_detail = su_get_message_url_detail(messageid);
  10248.     
  10249.     su_set_location(
  10250.                 url_detail.url,
  10251.                 null,
  10252.                 false);
  10253. }
  10254.  
  10255. function su_get_message_browser(messageid)
  10256. {
  10257.     return su_get_element("su_messageOuterBox" + messageid).parentNode.nextSibling;
  10258. }
  10259.  
  10260. function su_get_message_url_detail(messageid)
  10261. {
  10262.     return su_get_message_browser(messageid).su_url_detail;
  10263. }
  10264.  
  10265. function su_handle_message_cancel_command(messageid)
  10266. {
  10267.     su_get_element("su_bannerReplyButton" + messageid).disabled = false;    
  10268.     su_get_element("su_messageSendRow" + messageid).hidden = true;
  10269. }
  10270.  
  10271. function su_handle_message_send_command(messageid)
  10272. {
  10273.     su_send_reply_message(messageid);
  10274. }
  10275.  
  10276. function su_send_reply_message(messageid)
  10277. {
  10278.     var url_detail = su_get_message_url_detail(messageid);
  10279.     var note = su_get_element("su_messageTextbox" + messageid).value;
  10280.     note = su_trim(note);
  10281.     if (note == "")
  10282.     {
  10283.         alert("The reply is blank.");
  10284.         return;
  10285.     }
  10286.     
  10287.     var url = su_get_browser_url();
  10288.     
  10289.     var params = "";
  10290.     
  10291.     params = su_arp(params, "url", url);
  10292.     params = su_arp(params, "friend", url_detail.sender);
  10293.     params = su_arp(params, "note", note);
  10294.     params = su_arp(params, "referer", su_get_browser_referrer_url())
  10295.     
  10296.     var cmp_url = su_get_browser_url(null, true);
  10297.     if ((cmp_url.indexOf("http://video." + su_servername + "/#p") == 0) ||
  10298.             (cmp_url.indexOf("http://video." + su_servername + "/?p") == 0))
  10299.         params = su_arp(params, "videoperma", 1);
  10300.     
  10301.     su_post_url_server_async(
  10302.             "referral.php",
  10303.             params,
  10304.             15000,
  10305.             su_generic_done);
  10306.     
  10307.     var contact = su_ds.selectRow("contact", "nickname", url_detail.sender);
  10308.     if (contact && contact.contactid)
  10309.         su_ds.refreshAvatar(contact.contactid);
  10310.     
  10311.     su_close_message(messageid, true);
  10312.  
  10313.     su_increment_sendto("friend", url_detail.sender);
  10314.     su_register_activity("referral");
  10315.     
  10316.     var contact = su_ds.selectRow("contact", "nickname", url_detail.sender);
  10317.     if (contact && contact.contactid)
  10318.         su_ds.refreshAvatar(contact.contactid);
  10319.     su_refresh_referral_menu(5);
  10320. }
  10321.  
  10322. function su_handle_message_close_command(messageid)
  10323. {
  10324.     su_close_message(messageid, true);
  10325. }
  10326.  
  10327. function su_close_message(messageid, animate)
  10328. {
  10329.     var id = "su_messageOuterBox" + messageid;
  10330.     var el = su_get_element(id);
  10331.     if (! el)
  10332.         return;
  10333.     
  10334.     if (animate)
  10335.     {
  10336.         su_set_drawer_open(
  10337.                     id,
  10338.                     false,
  10339.                     function () { el.parentNode.removeChild(el); });
  10340.     }
  10341.     else
  10342.     {
  10343.         el.parentNode.removeChild(el);
  10344.     }
  10345. }
  10346.  
  10347. // called upon logout
  10348. function su_close_all_messages()
  10349. {
  10350.     var browsers = getBrowser().browsers;
  10351.     var i;
  10352.     var url_detail;
  10353.     for (i = 0; i < browsers.length; i++)
  10354.     {
  10355.         var browser = browsers[i];
  10356.         
  10357.         if (! browser.su_url_detail)
  10358.             continue;
  10359.         
  10360.         url_detail = browser.su_url_detail;
  10361.         
  10362.         delete browser.su_url_detail;
  10363.         
  10364.         if (! url_detail.messageid)
  10365.             continue;
  10366.         
  10367.         var id = "su_messageOuterBox" + url_detail.messageid;
  10368.         var el = su_get_element(id);
  10369.         if (el)
  10370.             el.parentNode.removeChild(el);
  10371.     }
  10372. }
  10373.  
  10374. // [kudos:] This xul-specific sliding code is derived from the
  10375. // _showNotification method of the Firefox notificationbox widget in
  10376. // source file mozilla/toolkit/content/widgets/notification.xml.
  10377. function su_set_drawer_open(id, state, callback, messageid)
  10378. {
  10379.     var el = su_get_element(id);
  10380.     var height = el.boxObject.height;
  10381.     var steps = 4;
  10382.     var delta = height / steps;
  10383.     var opacity_delta = 1 / steps;
  10384.     
  10385.     if (state)
  10386.     {
  10387.         el.style.removeProperty("position");
  10388.         el.style.removeProperty("top");
  10389.         el.style.marginTop = -height + "px";
  10390.         el.style.opacity = 0;
  10391.     }
  10392.     else
  10393.     {
  10394.         delta = -delta;
  10395.         opacity_delta = -opacity_delta;
  10396.     }
  10397.     
  10398.     var slide = function (callback, messageid)
  10399.     {
  10400.         var done = false;
  10401.         var style = window.getComputedStyle(el, null);
  10402.         var margin = style.getPropertyCSSValue("margin-top").
  10403.                     getFloatValue(CSSPrimitiveValue.CSS_PX);
  10404.  
  10405.         if (delta > 0 && margin + delta >= 0)
  10406.         {
  10407.             el.style.marginTop = "0px";
  10408.             el.style.opacity = 1;
  10409.             done = true;
  10410.         }
  10411.         else if (delta < 0 && margin + delta <= -height)
  10412.         {
  10413.             el.style.marginTop = -height + "px";
  10414.             done = true;
  10415.         }
  10416.         else
  10417.         {
  10418.             el.style.marginTop = (margin + delta).toFixed(4) + "px";
  10419.             el.style.opacity = Number(el.style.opacity) + opacity_delta;
  10420.         }
  10421.  
  10422.         if (done)
  10423.         {
  10424.             clearInterval(su_drawer_timers[id]);
  10425.             delete su_drawer_timers[id];
  10426.             if (callback)
  10427.                 setTimeout(callback, 100, messageid);
  10428.         }
  10429.     }
  10430.     
  10431.     su_drawer_timers[id] = setInterval(slide, 50, callback, messageid);
  10432. }
  10433.  
  10434. function su_display_info(info_type, optDomain)
  10435. {
  10436.     if (! su_host.ff3plus)
  10437.         return;
  10438.     
  10439.     if (! su_ds.getValue("$show_tutorial_info"))
  10440.         return;
  10441.  
  10442.     if ((! su_ds.hasFeature("$info_tutorial")) && (! su_test_info))
  10443.         return;
  10444.     
  10445.     // display info only if the toolbar is in default position
  10446.     if (su_ds.getValue("@toolbar-position") != "stumbleupon")
  10447.         return;
  10448.     
  10449.     if (! su_ds.getValue("@toolbar-visible"))
  10450.         return;
  10451.     
  10452.     // close the info if we change thru domain
  10453.     if (su_info_spec && optDomain && su_info_spec.domain && (su_info_spec.domain != optDomain))
  10454.     {
  10455.         su_close_info();
  10456.         return;
  10457.     }
  10458.     
  10459.     // Show only one info bubble per day.
  10460.     var now_s = su_get_time_s();
  10461.     var min_interval = 4 * 3600; // 4 hours
  10462.     var time_s = su_ds.getIntValue("$info_time_s"); 
  10463.  
  10464.     var spec = new Object();
  10465.     
  10466.     spec.closed = false;
  10467.     spec.type = info_type;
  10468.     spec.shown_interval_s = 0;
  10469.     spec.shown_time_s = null;
  10470.     
  10471.     switch (info_type)
  10472.     {
  10473.         case "rate":            
  10474.             if ((time_s && ((now_s - time_s) < min_interval)) && (! su_test_info))
  10475.                 return;
  10476.             spec.bubble_offset = (su_host.win) ? 0 : 2;
  10477.             spec.leader_offset = (su_host.win) ? -2 : 0;
  10478.             spec.target_id = "su_thumbup";
  10479.             spec.shown_pref = "$shown_rate_info";
  10480.             spec.message = "Friendly reminder:  If you rate pages as you go, the toolbar learns what you like and delivers more.";
  10481.             break;
  10482.         case "reviews":
  10483.             if ((time_s && ((now_s - time_s) < min_interval)) && (! su_test_info))
  10484.                 return;
  10485.             spec.bubble_offset = 7;
  10486.             spec.leader_offset = 5;
  10487.             spec.target_id = "su_website_info";
  10488.             spec.shown_pref = "$shown_reviews_info";
  10489.             spec.message = "Tip: The Reviews button lets you see what other Stumblers think of this site.";
  10490.             break;
  10491.         case "referral":
  10492.             if ((time_s && ((now_s - time_s) < min_interval)) && (! su_test_info))
  10493.                 return;
  10494.             spec.bubble_offset = (su_host.win) ? 0 : 2;
  10495.             spec.leader_offset = (su_host.win) ? -2 : 0;
  10496.             spec.target_id = "su_referral_menu";
  10497.             spec.shown_pref = "$shown_referral_info";
  10498.             spec.message = "Tidbit: You can share a good website with friends or any email address.";
  10499.             break;
  10500.         case "thru_domain":
  10501.             if ((time_s && ((now_s - time_s) < min_interval)) && (! su_test_info))
  10502.                 return;
  10503.             spec.bubble_offset = (su_host.win) ? 5 : 7;
  10504.             spec.leader_offset = (su_host.win) ? 3 : 5;
  10505.             spec.domain = optDomain;
  10506.             spec.target_id = "su_mode_domain";
  10507.             spec.shown_pref = null;
  10508.             if (su_ds.getValue("$shown_thru_domain_info_count"))
  10509.                 spec.message = su_ds.lookup("domain:info_message", optDomain);
  10510.             else
  10511.                 spec.message = su_ds.lookup("domain:info_message_simple", optDomain);
  10512.             if (! spec.message)
  10513.                 spec.message = "Click here to Stumble thru " + su_ds.getThruDomainChannel(optDomain).name + ".";
  10514.             break;
  10515.         case "photo":
  10516.             if ((time_s && ((now_s - time_s) < min_interval)) && (! su_test_info))
  10517.                 return;
  10518.             spec.bubble_offset = (su_host.win) ? 5 : 7;
  10519.             spec.leader_offset = (su_host.win) ? 3 : 5;
  10520.             spec.target_id = "su_mode_photo";
  10521.             spec.shown_pref = "$shown_photo_info";
  10522.             spec.message = "Tip: You can discover more of the web's best images in the Photos channel.";
  10523.             break;
  10524.         case "video":
  10525.             
  10526.             break;
  10527.         case "photo_praise":
  10528.             spec.bubble_offset = (su_host.win) ? 5 : 7;
  10529.             spec.leader_offset = (su_host.win) ? 3 : 5;
  10530.             spec.target_id = "su_mode_all";
  10531.             spec.shown_pref = "$shown_toall_info";
  10532.             spec.message = "Enjoy the photos!  The globe button changes back to the 'All' channel.";
  10533.             su_close_info();
  10534.             setTimeout(su_refresh_info, 3000);
  10535.             break;
  10536.         case "thru_domain_praise_toall":
  10537.             spec.bubble_offset = (su_host.win) ? 5 : 7;
  10538.             spec.leader_offset = (su_host.win) ? 3 : 5;
  10539.             spec.target_id = "su_mode_all";
  10540.             spec.shown_pref = "$shown_toall_info";
  10541.             spec.message = "Have fun with " + su_ds.getThruDomainChannel(optDomain).name + " pages!  The globe button changes back to the 'All' channel.";
  10542.             su_close_info();
  10543.             setTimeout(su_refresh_info, 3000);
  10544.             break;
  10545.         case "thru_domain_praise_tomore":
  10546.             spec.bubble_offset = (su_host.win) ? 0 : 2;
  10547.             spec.leader_offset = (su_host.win) ? -2 : 0;
  10548.             spec.domain = optDomain;
  10549.             spec.target_id = "su_mode_more";
  10550.             spec.shown_pref = "$shown_tomore_info";
  10551.             spec.message = null; // overridden
  10552.             su_close_info();
  10553.             setTimeout(su_refresh_info, 3000);
  10554.             break;
  10555.         default:
  10556.             return;
  10557.     }
  10558.     
  10559.     su_info_spec = spec;
  10560.     su_ds.setValue("#recent_info_spec", spec);
  10561.     
  10562.     try {
  10563.         su_refresh_info();
  10564.     } catch (e) { su_log_error("REFRESH INFO", e); } 
  10565. }
  10566.  
  10567. function su_refresh_info()
  10568. {
  10569.     var toolbar = su_get_element("su_info_toolbar");
  10570.     if (! su_info_spec)
  10571.     {
  10572.         toolbar.collapsed = true;
  10573.         return;
  10574.     }
  10575.     
  10576.     var spec = su_info_spec;
  10577.     var target_el = su_get_element(spec.target_id);
  10578.     
  10579.     if ((target_el.boxObject.width == 0) || spec.closed)
  10580.     {
  10581.         su_hide_info();
  10582.         return;
  10583.     }
  10584.     
  10585.     
  10586.     // record the 'shown info' event
  10587.     
  10588.     var i;
  10589.     var found;
  10590.     var first_thru_domain = false;
  10591.     if (spec.shown_pref)
  10592.     {
  10593.         su_ds.setValue(spec.shown_pref, true);
  10594.     }
  10595.     else if (spec.type == "thru_domain")
  10596.     {
  10597.         var domains = su_ds.getValue("$shown_thru_domain_info_list").split(":");
  10598.         if (domains.length)
  10599.         {
  10600.             found = false;
  10601.             for (i = 0; i < domains.length; i++)
  10602.             {
  10603.                 if (domains[i] == spec.domain)
  10604.                     found = true;
  10605.             }
  10606.             
  10607.             if (! found)
  10608.             {
  10609.                 var count = su_ds.incrementValue("$shown_thru_domain_info_count");
  10610.                 if (count == 1)
  10611.                 {
  10612.                     su_ds.setValue("$shown_thru_domain_info_list", spec.domain);
  10613.                 }
  10614.                 else
  10615.                 {
  10616.                     domains.push(spec.domain);
  10617.                     su_ds.setValue("$shown_thru_domain_info_list", domains.join(":"));
  10618.                 }    
  10619.             }
  10620.         }    
  10621.         else
  10622.         {
  10623.             su_ds.incrementValue("$shown_thru_domain_info_count");
  10624.             su_ds.setValue("$shown_thru_domain_info_list", spec.domain);
  10625.         }
  10626.     }
  10627.  
  10628.     var now_s = su_get_time_s();
  10629.     
  10630.     su_ds.setValue("$info_time_s", now_s);
  10631.     
  10632.     su_ds.flushPrefs();
  10633.     
  10634.     spec.shown_time_s = now_s;
  10635.     
  10636.     // If an old container exists, fix the toolbar height to avoid
  10637.     // collapse/reflow upon browser resize.  Then nuke the old
  10638.     // container.  
  10639.     
  10640.     var container = su_get_element("su_info_container");    
  10641.  
  10642.     if (container)
  10643.     {
  10644.         toolbar.style.height = toolbar.boxObject.height + "px";
  10645.         toolbar.removeChild(container);
  10646.     }    
  10647.     
  10648.     
  10649.     // construct the speech bubble
  10650.     
  10651.     var x = target_el.boxObject.screenX - toolbar.boxObject.screenX + Math.round(target_el.boxObject.width / 2);
  10652.     
  10653.     var el;
  10654.     var vbox;
  10655.     var hbox;
  10656.     var text;
  10657.     var style;
  10658.     var vbox;
  10659.     var content_el;
  10660.     
  10661.     container = document.createElement("hbox");
  10662.     container.setAttribute("id", "su_info_container");
  10663.     container.setAttribute("style", "position: absolute; height: 0; width: 0; margin-bottom: 2px;");
  10664.     toolbar.appendChild(container);
  10665.     
  10666.     var bubble_outerbox = document.createElement("hbox");
  10667.     style = "position: absolute; left: " + (x + spec.bubble_offset) + "px; top: 1px;";
  10668.     bubble_outerbox.setAttribute("style", style);
  10669.     container.appendChild(bubble_outerbox);
  10670.     
  10671.     var bubble_midbox = document.createElement("hbox");
  10672.     bubble_outerbox.appendChild(bubble_midbox);
  10673.     
  10674.     var bubble = document.createElement("hbox");
  10675.     style = "border-color: rgb(247,182,0); border-style: solid; border-width: 3px; font-weight: normal; font-size: 12pt; color: black; background-color: rgb(255,255,189); -moz-border-radius-topright: 15px; -moz-border-radius-bottomright: 15px; -moz-border-radius-bottomleft: 15px; -moz-border-radius-topleft: 15px; padding-top: 2px; padding-bottom: 2px; padding-left: 15px; padding-right: 12px;";
  10676.     bubble.setAttribute("id", "su_info_bubble");
  10677.     bubble.setAttribute("style", style);
  10678.     if (su_host.mac)
  10679.         bubble.setAttribute("class", "su_pinstripe_infoMessage");
  10680.     else
  10681.         bubble.setAttribute("class", "su_winstripe_infoMessage");
  10682.     bubble_midbox.appendChild(bubble);
  10683.     
  10684.     vbox = document.createElement("vbox");
  10685.     bubble_midbox.appendChild(vbox);
  10686.     
  10687.     el = document.createElement("spacer");
  10688.     el.setAttribute("flex", "1");
  10689.     vbox.appendChild(el);
  10690.     
  10691.     var optout = document.createElement("checkbox");
  10692.     optout.setAttribute("label", "Show tips");
  10693.     optout.setAttribute("checked", su_ds.getValue("$show_tutorial_info"));
  10694.     optout.setAttribute("style", "margin-left: 15px;");
  10695.     optout.setAttribute("hidden", "true");
  10696.     optout.setAttribute("oncommand", "su_handle_info_optout_command(this)");
  10697.     vbox.appendChild(optout);
  10698.     
  10699.     var bubble_hbox = document.createElement("hbox");
  10700.     bubble.appendChild(bubble_hbox);
  10701.  
  10702.     // construct bubble content
  10703.     switch (spec.type)
  10704.     {
  10705.         case "thru_domain_praise_tomore":
  10706.             vbox = document.createElement("vbox");
  10707.             vbox.setAttribute("pack", "top");
  10708.             bubble_hbox.appendChild(vbox);
  10709.             content_el = document.createElement("label");
  10710.             if (su_host.win)
  10711.                 content_el.setAttribute("style", "margin-right: 20px; font-size: 17px;");
  10712.             else
  10713.                 content_el.setAttribute("style", "margin-right: 20px; font-size: 15px;");
  10714.             vbox.appendChild(content_el);
  10715.             var seq = su_ds.lookup("domain:tomore_favicon_list", spec.domain);
  10716.             if (seq)
  10717.             {
  10718.                 text = document.createTextNode("Have fun with " + su_ds.getThruDomainChannel(spec.domain).name + " pages! You can StumbleThru this and other websites ");
  10719.                 content_el.appendChild(text);
  10720.                 var domains = seq.split(",");
  10721.                 for (i = 0; i < domains.length; i++)
  10722.                 {
  10723.                     hbox = document.createElement("hbox");
  10724.                     hbox.setAttribute("style", "padding-right:4px;");
  10725.                     content_el.appendChild(hbox);
  10726.                     if (i == 0)
  10727.                     {
  10728.                         text = document.createTextNode("(");
  10729.                         hbox.appendChild(text);
  10730.                     }
  10731.                     vbox = document.createElement("vbox");
  10732.                     if (i == 0)
  10733.                         vbox.setAttribute("style", "padding-top:2px; padding-left:2px;");
  10734.                     else
  10735.                         vbox.setAttribute("style", "padding-top:2px;");
  10736.                     hbox.appendChild(vbox);
  10737.                     el = document.createElement("image");
  10738.                     el.setAttribute("width", "16");
  10739.                     el.setAttribute("height", "16");
  10740.                     el.setAttribute("src", su_get_favicon_url(domains[i]));
  10741.                     el.setAttribute("tooltiptext", su_ds.getThruDomainChannel(domains[i]).name);
  10742.                     vbox.appendChild(el);
  10743.                     text = document.createTextNode(",");
  10744.                     hbox.appendChild(text);
  10745.                 }
  10746.                 text = document.createTextNode("etc.) anytime.");
  10747.                 content_el.appendChild(text);
  10748.             }
  10749.             else
  10750.             {
  10751.                 text = document.createTextNode("You can StumbleThru " + su_ds.getThruDomainChannel(spec.domain).name + " anytime.");
  10752.                 content_el.appendChild(text);
  10753.             }
  10754.             vbox = document.createElement("vbox");
  10755.             vbox.setAttribute("pack", "top");
  10756.             bubble_hbox.appendChild(vbox);
  10757.             break;
  10758.         default:
  10759.             vbox = document.createElement("vbox");
  10760.             vbox.setAttribute("pack", "top");
  10761.             bubble_hbox.appendChild(vbox);
  10762.             content_el = document.createElement("label");
  10763.             if (su_host.win)
  10764.                 content_el.setAttribute("style", "margin-right: 20px; margin-top: 2px; font-size: 17px;");
  10765.             else
  10766.                 content_el.setAttribute("style", "margin-right: 20px; margin-top: 4px; font-size: 15px;");
  10767.             vbox.appendChild(content_el);
  10768.             text = document.createTextNode(spec.message);
  10769.             content_el.appendChild(text);
  10770.             vbox = document.createElement("vbox");
  10771.             vbox.setAttribute("pack", "top");
  10772.             bubble_hbox.appendChild(vbox);
  10773.             break;
  10774.     }
  10775.     
  10776.     el = document.createElement("toolbarbutton");
  10777.     if (su_host.mac)
  10778.         el.setAttribute("class", "su_pinstripe_messageCloseButton");
  10779.     else
  10780.         el.setAttribute("class", "su_winstripe_messageCloseButton");
  10781.     el.setAttribute("style", "margin-top: 4px;");
  10782.     el.setAttribute("oncommand", "su_handle_close_info_command()");
  10783.     bubble_hbox.appendChild(el);
  10784.     
  10785.     // If the bubble overflows with window.innerWidth, narrow the label.
  10786.     var toolbox = su_get_element("navigator-toolbox");
  10787.     var right_edge = (bubble_outerbox.boxObject.screenX - toolbox.boxObject.screenX) + bubble_outerbox.boxObject.width;
  10788.     var width = content_el.boxObject.width;
  10789.     bubble_outerbox.hidden = true;
  10790.     var right_margin_width = window.innerWidth - right_edge;
  10791.     if (right_margin_width < 0)
  10792.         content_el.style.width = (width + right_margin_width) + "px";
  10793.     else if (right_margin_width > 110)
  10794.         optout.hidden = false;
  10795.     bubble_outerbox.hidden = false;
  10796.     
  10797.     // Add the arrow leader.
  10798.     el = su_create_html_element("img");
  10799.     if (su_host.win)
  10800.         style = "position: absolute; left: " + (x - Math.round(25 / 2) + spec.leader_offset) + "px; top: -5px; width: 18px; height: 34px";
  10801.     else
  10802.         style = "position: absolute; left: " + (x - Math.round(25 / 2) + spec.leader_offset) + "px; top: -10px; width: 18px; height: 34px";
  10803.     el.setAttribute("style", style);
  10804.     if (su_host.win)
  10805.         el.setAttribute("src", "chrome://stumbleupon/content/skin/arrow_green-c.png");
  10806.     else
  10807.         el.setAttribute("src", "chrome://stumbleupon/content/skin/arrow_green-b.png");
  10808.     el.setAttribute("onclick", "su_handle_info_leader_click()");
  10809.     container.appendChild(el);
  10810.     
  10811.     if (right_margin_width <= 110)
  10812.     {
  10813.         // Add the optout2 box.
  10814.         el = su_create_html_element("div");
  10815.         style = "position: absolute; left: " + (x - Math.round(25 / 2) + spec.leader_offset - 100) + "px; top: " + (bubble_outerbox.boxObject.height - 20) + "px;";
  10816.         el.setAttribute("style", style)
  10817.         container.appendChild(el);
  10818.         
  10819.         var optout2 = document.createElement("checkbox");
  10820.         optout2.setAttribute("label", "Show tips");
  10821.         optout2.setAttribute("checked", su_ds.getValue("$show_tutorial_info"));
  10822.         optout2.setAttribute("oncommand", "su_handle_info_optout_command(this)");
  10823.         el.appendChild(optout2);
  10824.     }
  10825.     
  10826.     toolbar.style.height = "auto";
  10827.     toolbar.collapsed = false;
  10828. }
  10829.  
  10830. function su_handle_info_leader_click()
  10831. {
  10832.     su_dispatch_click(document, su_info_spec.target_id);
  10833. }
  10834.  
  10835. function su_create_html_element(lowercase_tag_name)
  10836. {
  10837.     return document.createElementNS("http://www.w3.org/1999/xhtml", "html:" + lowercase_tag_name);
  10838. }
  10839.  
  10840. function su_handle_close_info_command()
  10841. {
  10842.     su_close_info();
  10843. }
  10844.  
  10845. function su_handle_info_optout_command(el)
  10846. {
  10847.     su_ds.setValue("$show_tutorial_info", el.checked);
  10848. }
  10849.  
  10850. function su_hide_info()
  10851. {
  10852.     if (! su_info_spec)
  10853.         return;
  10854.     
  10855.     var spec = su_info_spec;
  10856.     if (spec.shown_time_s)
  10857.     {
  10858.         spec.shown_interval_s += su_get_time_s() - spec.shown_time_s;
  10859.         spec.shown_time_s = null;
  10860.     }
  10861.     if (spec.shown_interval_s >= 8)
  10862.         su_close_info();
  10863.     else
  10864.         toolbar.collapsed = true;
  10865.     return;
  10866. }
  10867.  
  10868. function su_close_info()
  10869. {
  10870.     var el = su_get_element("su_info_container");    
  10871.     if (el)
  10872.         el.parentNode.removeChild(el);
  10873.     
  10874.     if (su_info_spec)
  10875.         su_info_spec.closed = true;
  10876.     
  10877.     su_get_element("su_info_toolbar").collapsed = true;
  10878. }
  10879.  
  10880. function su_handle_send_dialog_accept(detail)
  10881. {
  10882.     var url = detail.url;
  10883.     
  10884.     var params = "";
  10885.     var contact;
  10886.     
  10887.     switch (detail.mode)
  10888.     {
  10889.         case "send":
  10890.             
  10891.             params = su_arp(params, "url", detail.url);
  10892.             params = su_arp(params, "friend", detail.target);
  10893.             params = su_arp(params, "note", detail.message);
  10894.             params = su_arp(params, "referer", detail.referrer_url);
  10895.             
  10896.             if (detail.stumblevideo)
  10897.                 params = su_arp(params, "videoperma", 1);
  10898.     
  10899.             su_post_url_server_async(
  10900.                     "referral.php",
  10901.                     params,
  10902.                     15000,
  10903.                     su_generic_done);
  10904.             su_increment_sendto("friend", detail.target);
  10905.             su_register_activity("referral");
  10906.             contact = su_ds.selectRow("contact", "nickname", detail.target);
  10907.             if (contact && contact.contactid)
  10908.                 su_ds.refreshAvatar(contact.contactid);
  10909.             su_refresh_referral_menu(6);
  10910.             break;
  10911.         case "email":
  10912.             
  10913.             params = su_arp(params, "url", detail.url);
  10914.             params = su_arp(params, "recipient", detail.target);
  10915.             params = su_arp(params, "title", detail.title);
  10916.             params = su_arp(params, "note", detail.message);
  10917.             params = su_arp(params, "referer", detail.referrer_url);
  10918.             
  10919.             if (detail.stumblevideo)
  10920.                 params = su_arp(params, "videoperma", 1);
  10921.     
  10922.             su_post_url_server_async(
  10923.                     "mailit.php",
  10924.                     params,
  10925.                     15000,
  10926.                     su_generic_done);
  10927.  
  10928.             // We increment here rather than in email_done() because we don't
  10929.             // want the menupopup closing that occurs in 
  10930.             // refresh_referral_menu() to occur after a network delay of 
  10931.             // indeterminant length by which time the user may already be 
  10932.             // attempting to send to someone else. -- JW
  10933.             su_increment_sendto("email", detail.target);
  10934.             su_refresh_referral_menu(7);
  10935.             break;
  10936.     }
  10937. }
  10938.  
  10939. // Handler for menitem "Suggest New Interests"
  10940. function su_suggest()
  10941. {
  10942.     getBrowser().contentDocument.location = su_serverhttp + "suggest_interests.php";
  10943. }
  10944.  
  10945. // Handler for menuitem "Update Interests"
  10946. function su_interests()
  10947. {
  10948.     if (stumbleid == 0)
  10949.         return;
  10950.     
  10951.     // Redirect to interests page
  10952.     var loc = su_serverhttp + "interests.php";
  10953.     
  10954.     //!!! disabled because it screws up history
  10955.     // if (su_get_browser_url() != loc)
  10956.     
  10957.     getBrowser().contentDocument.location = loc;
  10958. }
  10959.  
  10960. // Handler for button "Toolbar Preferences"
  10961. function su_preferences(opt_initial_tab)
  10962. {
  10963.     if (stumbleid == 0)
  10964.         return;
  10965.     
  10966.     var detail = new Object();
  10967.     detail.initial_tab = (opt_initial_tab) ? opt_initial_tab : null;
  10968.     
  10969.     su_unfocus_searchbox(); 
  10970.     window.openDialog(
  10971.                 "chrome://stumbleupon/content/preferenceDialog.xul",
  10972.                 "su_preferences",
  10973.                 "chrome,dialog,centerscreen,dependent",
  10974.                 detail);
  10975. }
  10976.  
  10977. function su_handle_preference_dialog_accept()
  10978. {
  10979.     var toolbar_position = su_ds.getValue("@toolbar-position");
  10980.     var toolbar = su_get_element(toolbar_position);
  10981.     if (! toolbar)
  10982.     {
  10983.         su_log_error(
  10984.                     "MOVE FAILSAFE3",
  10985.                     new Object(),
  10986.                     toolbar_position,
  10987.                     su_ds.getValue("@position-group"));
  10988.         
  10989.         setTimeout(alert, 50, 
  10990.                     "The specified toolbar movement cannot be completed.\n\n" +
  10991.                     "The default position will be used.\n\n");
  10992.         
  10993.         su_ds.setValue("@toolbar-position", "stumbleupon");
  10994.         su_ds.setValue("@position-group", "first");
  10995.     }
  10996.     
  10997.     try {
  10998.         su_move_toolbar(true, 6);
  10999.     } catch (e) { su_log_error("PREFERENCE MOVE", e, su_ds.getValue("@toolbar-position"), su_ds.getValue("@position-group")); } 
  11000.     
  11001.     try {
  11002.         su_refresh_toggle_button(true);
  11003.     } catch (e) { su_log_error("PREFERENCE TOGGLE", e); } 
  11004.  
  11005.     var detail = new Object();
  11006.     detail.from_preference_dialog = true;
  11007.     su_invoke_global_event("configure-toolbar", detail);
  11008.     su_preference_dialog = null;
  11009.     
  11010.     setTimeout(su_verify_toolbar_move, 0, 6);
  11011. }
  11012.  
  11013. // called during the global configure-toolbar event and during init
  11014. // to set labels for top-level toolbar elements
  11015. function su_init_labels()
  11016. {
  11017.     var ids;
  11018.     if (su_promo_mode && (stumbleid == 0))
  11019.     {
  11020.         ids = new Array(
  11021.             "su_thumbup",
  11022.             "su_referral_promo",
  11023.             "su_website_info_promo",
  11024.             "su_sites_promo",
  11025.             "su_video_promo",
  11026.             "su_profile",
  11027.             "su_friends",
  11028.             "su_referral_menu");
  11029.     }
  11030.     else
  11031.     {
  11032.         ids = new Array(
  11033.             "su_stumble",
  11034.             "su_thumbup",
  11035.             "su_recthumbup",
  11036.             "su_profile",
  11037.             "su_friends",
  11038.             "su_page_feature_prompt",
  11039.             "su_referral_menu",
  11040.             "su_website_info",
  11041.             "su_mode",
  11042.             "su_sponsor",
  11043.             "firstrater",
  11044.             "su_stumble_menu");
  11045.     }
  11046.     
  11047.     for (var i = 0; i < ids.length; i++)
  11048.     {
  11049.         if (ids[i] == "su_thumbup")
  11050.         {
  11051.             var element = su_get_element("su_thumbup");
  11052.             
  11053.             if (element.label == element.getAttribute("showlabel2"))
  11054.                 su_set_label("su_thumbup", element.getAttribute("showlabel2"));
  11055.             else
  11056.                 su_set_label("su_thumbup", null);
  11057.         }
  11058.         else if (ids[i] == "su_recthumbup")
  11059.         {
  11060.             if (stumbleid)
  11061.                 su_set_label("su_recthumbup", su_ds.getValue("$dd_rec_label"));
  11062.         }
  11063.         else
  11064.         {
  11065.             su_set_label(ids[i], null);
  11066.         }
  11067.     }
  11068. }
  11069.  
  11070. // Handler for button "Invite Friends"
  11071. function su_invite(event)
  11072. {
  11073.     // Redirect to home
  11074.     var loc = "find_friends.php";
  11075.     var params = null;
  11076.     if (su_ds.getValue("@facebook_user"))
  11077.     {
  11078.         loc = su_arp(loc, "pre", "facebook", true);
  11079.         var client_count = su_ds.getValue("@facebook_client_invite_count");
  11080.         client_count++;
  11081.         su_ds.setValue("@facebook_client_invite_count", client_count);
  11082.         params = su_arp("", "fbclientcount", client_count);
  11083.         params = su_arp(params, "fbsessioncount",
  11084.                     su_ds.incrementValue("#find_friends_facebook_count"));
  11085.         
  11086.         if (stumbleid != 0)
  11087.         {
  11088.             var count = su_ds.getValue("$facebook_invite_count");
  11089.             count++;
  11090.             su_ds.setValue("$facebook_invite_count", count);
  11091.             params = su_arp(params, "fbcount", count);
  11092.         }
  11093.     }
  11094.     
  11095.     if (stumbleid != 0)
  11096.         su_ds.setValue("$shown_find_friends", true);
  11097.     
  11098.     if (su_host.dist)
  11099.         loc = su_arp(loc, "dist", su_host.dist, true);
  11100.     
  11101.     su_set_server_location(
  11102.                 loc,
  11103.                 params,
  11104.                 su_new_tab(event));
  11105. }
  11106.  
  11107. // Handler for button "Upgrade Now"
  11108. function su_sponsor(extra)
  11109. {
  11110.     if (stumbleid == 0)
  11111.         return;
  11112.  
  11113.     // Redirect to sponsor page
  11114.     getBrowser().contentDocument.location = su_serverhttp + "sponsors.php" + extra;
  11115. }
  11116.  
  11117. // handler for profile tab buttons
  11118. function su_redir_tab(event, tab)
  11119. {
  11120.     try {
  11121.     
  11122.     if (su_promo_mode && (stumbleid == 0))
  11123.     {
  11124.         if (tab == "")
  11125.             tab = "favorites";
  11126.         su_handle_promo_click(event, tab);
  11127.         return true;
  11128.     }
  11129.     
  11130.     if (su_overflow_popup_open)
  11131.     {
  11132.         var popup = su_get_element("su_overflow_popup");
  11133.         if ((typeof popup.hidePopup) == "function")
  11134.             popup.hidePopup();
  11135.  
  11136.         su_unfocus();
  11137.     }
  11138.     
  11139.     if (stumbleid == 0)
  11140.         return true;
  11141.  
  11142.     su_set_profile_location(tab, su_new_tab(event));
  11143.     
  11144.     } catch (e) { su_log_error("HANDLE TAB", e); }
  11145.     
  11146.     return true;
  11147. }
  11148.  
  11149. // Sends stumble stats to server (urls and dates you've stumbled upon)
  11150. function su_upload_stumbles()
  11151. {
  11152.     if (su_ds.getValue("$stumblestats") == "")
  11153.     {
  11154.         return;
  11155.     }
  11156.     
  11157.     var context = new su_AsyncContext();
  11158.     context.oldStumbleReport = true;
  11159.     context.quiet = true;
  11160.     
  11161.     var params = "";
  11162.     params = su_arp(params, "urlids", su_ds.getValue("$stumblestats")); 
  11163.     params = su_arp(params, "timestamps", su_ds.getValue("$stumbletimes")); 
  11164.     params = su_arp(params, "types", su_ds.getValue("$stumbletypes")); 
  11165.     params = su_arp(params, "referralids", su_ds.getValue("$stumblereferrals"));
  11166.     params = su_arp(params, "clienttime", su_get_time_s());
  11167.     params = su_arp(params, "houroffset", Math.floor((new Date()).getTimezoneOffset() / 60));
  11168.     su_post_url_server_async(
  11169.                 "stumbles.php",
  11170.                 params,
  11171.                 15000,
  11172.                 su_upload_stumbles_done,
  11173.                 context);
  11174. }
  11175.  
  11176. function su_upload_stumbles_done(res)
  11177. {
  11178.     var context = res.detail;
  11179.  
  11180.     if (res.status != 200)
  11181.         return;
  11182.     
  11183.     var s = "";
  11184.     if (typeof(res.responseText) != "undefined")
  11185.         s = res.responseText;
  11186.     
  11187.     if (su_log_communication)
  11188.         su_log("response stumbles.php", s);
  11189.     
  11190.     su_process_commands(s, context);
  11191. }
  11192.  
  11193. // Get rid of the stumble queue
  11194. function clear_stumbles()
  11195. {
  11196.     stumbles = new Array();
  11197. //    su_fu.remove(su_prefDir + "stumbleurls");
  11198.     su_write_file_user("stumbleurls", "");
  11199.     try {
  11200.         su_prefetcher.clearTargets();
  11201.     } catch (e) { su_log_error("PREFETCHER 5", e); }
  11202. }
  11203.  
  11204. function su_set_inbox_status(icon)
  11205. {
  11206.     var message_element = su_get_element("su_messages");
  11207.     var newimage = "chrome://stumbleupon/content/skin/mail" + icon + ".png";
  11208.     su_set_image("su_messages", newimage);
  11209.     
  11210.     // right now we don't save between sessions
  11211.     if (icon == 2)
  11212.     {
  11213.         su_ds.setValue("$newmessage", true);
  11214.         if ((! su_ds.getValue("$show_messages")) && (! su_new_user))
  11215.             su_set_visible("su_messages", true);
  11216.     }
  11217.     else
  11218.     {
  11219.         su_set_visible("su_messages", su_ds.getValue("$show_messages"));
  11220.         su_ds.setValue("$newmessage", false);
  11221.     }
  11222.     su_ds.flushPrefs();
  11223. }
  11224.  
  11225. function su_sendto(friend)
  11226. {
  11227.     if (stumbleid == 0)
  11228.         return;
  11229.     
  11230.     var current_page = su_get_browser_url();
  11231.  
  11232.     if (current_page.indexOf("about:") == 0)
  11233.         return;
  11234.  
  11235.     su_unfocus_searchbox(); 
  11236.  
  11237.     var detail = new Object();
  11238.     detail.mode = "send";
  11239.     detail.target = friend;
  11240.     detail.url = current_page;
  11241.     detail.display_url = su_get_browser_url(null, true);
  11242.     detail.stumblevideo = (su_get_stumblevideo_detail() != null);
  11243.     detail.dialog_title = "Send to " + detail.target;
  11244.     detail.show_target = su_host.mac;
  11245.     detail.referrer_url = su_get_browser_referrer_url();
  11246.  
  11247.     window.openDialog(
  11248.                 "chrome://stumbleupon/content/sendDialog.xul",
  11249.                 "",
  11250.                 "chrome,dialog,centerscreen,dependent", 
  11251.                 detail);
  11252. }
  11253.  
  11254. // called by sendto() and mailit() to increment the sendto count in 
  11255. // sendto_stats
  11256. function su_increment_sendto(key_type, key)
  11257. {
  11258.     var contact;
  11259.     var field_name;
  11260.     if (key_type == "friend")
  11261.         field_name = "nickname";
  11262.     else if (key_type == "email")
  11263.         field_name = "email";
  11264.     
  11265.     contact = su_ds.selectRow("contact", field_name, key);
  11266.     var new_contact = false;
  11267.     if (! contact)
  11268.     {
  11269.         new_contact = true;
  11270.         contact = new Object()
  11271.         contact[field_name] = key;
  11272.     }
  11273.  
  11274.     if (contact.referral_count)
  11275.         contact.referral_count++;
  11276.     else
  11277.         contact.referral_count = 1;
  11278.  
  11279.     contact.referral_timestamp = (new Date()).getTime();
  11280.  
  11281.     if (new_contact)
  11282.         su_ds.insertRow("contact", contact);
  11283.     else
  11284.         su_ds.updateRow(contact);
  11285.  
  11286.     su_ds.flushPrefs();
  11287. }
  11288.  
  11289. function su_share_facebook()
  11290. {
  11291.     var params = "";
  11292.     params = su_arp(params, "url", su_get_browser_url());
  11293.     params = su_arp(params, "target", "facebook");
  11294.     var context = { target: "facebook",  share: true };
  11295.     su_post_url_server_async(
  11296.                 "suprshare.php",
  11297.                 params,
  11298.                 15000,
  11299.                 su_verbose_generic_done,
  11300.                 context);
  11301. }
  11302.  
  11303. function su_share_twitter()
  11304. {
  11305.     var params = "";
  11306.     params = su_arp(params, "url", su_get_browser_url());
  11307.     params = su_arp(params, "target", "twitter");
  11308.     var context = { target: "twitter", share: true };
  11309.     su_post_url_server_async(
  11310.                 "suprshare.php",
  11311.                 params,
  11312.                 15000,
  11313.                 su_verbose_generic_done,
  11314.                 context);
  11315. }
  11316.  
  11317. function su_append_twitter_facebook_menuitem(menu, has_avatar)
  11318. {
  11319.     var item = document.createElement("menuitem");
  11320.  
  11321.     item.setAttribute("label", "Facebook");
  11322.     item.setAttribute("tooltiptext", "Share on Facebook");
  11323.     item.setAttribute("oncommand", "su_share_facebook()");
  11324.     item.setAttribute("image", "chrome://stumbleupon/content/skin/favicon_facebook.gif");
  11325.     if (has_avatar)
  11326.             item.setAttribute("class", "menuitem-iconic su-iconic-referral");
  11327.     else
  11328.             item.setAttribute("class", "menuitem-iconic");
  11329.     menu.appendChild(item);
  11330.  
  11331.     var item = document.createElement("menuitem");
  11332.     item.setAttribute("label", "Twitter");
  11333.     item.setAttribute("tooltiptext", "Share on Twitter");
  11334.     item.setAttribute("oncommand", "su_share_twitter()");
  11335.     item.setAttribute("image", "chrome://stumbleupon/content/skin/favicon_twitter.gif");
  11336.     if (has_avatar)
  11337.         item.setAttribute("class", "menuitem-iconic su-iconic-referral");
  11338.     else
  11339.         item.setAttribute("class", "menuitem-iconic");
  11340.     menu.appendChild(item);
  11341.  
  11342. }
  11343.  
  11344. function su_refresh_referral_menu(from)
  11345. {
  11346.     su_invoke_global_event("referral-menu-dirty", null, from);
  11347.     
  11348.     if (su_refreshing_referral_menu)
  11349.         return;
  11350.  
  11351.     su_refreshing_referral_menu = true;
  11352.     
  11353.     setTimeout(
  11354.                 function (win, from) {
  11355.                     win.su_invoke_global_event("update-referral-menu", null, from); },
  11356.                 1000,
  11357.                 window,
  11358.                 from);
  11359. }
  11360.  
  11361. // utility object for refresh_referral_menu()
  11362. function su_SendObj(type, contact)
  11363. {
  11364.     this.type = type;
  11365.     if (type == "friend")
  11366.         this.name = contact.nickname;
  11367.     else if (type == "email")
  11368.         this.name = contact.email;
  11369.     
  11370.     this.count = (contact.referral_count) ? contact.referral_count : 0;
  11371.     this.timestamp = (contact.referral_timestamp) ? contact.referral_timestamp : 0;
  11372.     this.compare_name = this.name.toLowerCase();
  11373.     
  11374.     this.avatar_url = "";
  11375.     
  11376.     if (contact.iconpic)
  11377.     {
  11378.         if (su_ds.isResourceInstalled("iconpics", contact.contactid + ".jpg"))
  11379.             this.avatar_url = su_ds.getResourceURLFromName("iconpics", contact.contactid + ".jpg");
  11380.     }
  11381. }
  11382.  
  11383. function su_update_referral_menu()
  11384. {
  11385.     su_refreshing_referral_menu = false;
  11386.     if (! su_referral_menu_dirty)
  11387.         return;
  11388.     
  11389.     if (su_referral_popup_open)
  11390.         return;
  11391.     
  11392.     setTimeout(su_update_referral_menu2, 0);
  11393. }
  11394.  
  11395. function su_update_referral_menu2()
  11396. {
  11397.     if (su_referral_popup_open)
  11398.         return;
  11399.  
  11400.     su_refreshing_referral_menu = false;
  11401.     su_referral_menu_dirty = false;
  11402.     
  11403.     try {
  11404.  
  11405.     var i, j, ja, count;
  11406.     
  11407.     var menu = su_get_element("su_referral_menu");
  11408.     // Delete it if it already exists.
  11409.     var el = su_get_element("su_referral_popup");
  11410.     if (el)
  11411.         el.parentNode.removeChild(el);
  11412.     
  11413.     var referral_popup = document.createElement("menupopup");
  11414.     var popup;
  11415.     
  11416.     referral_popup.setAttribute("id", "su_referral_popup");
  11417.     referral_popup.setAttribute("onpopupshowing", "su_handle_popupshowing(event);");
  11418.     referral_popup.setAttribute("onpopuphidden", "su_handle_popuphidden(event);");
  11419.     menu.appendChild(referral_popup);
  11420.     
  11421.     if (su_referral_popup_open)
  11422.     {
  11423.         referral_popup.hidePopup();
  11424.         su_unfocus();
  11425.     }
  11426.     
  11427.     
  11428.     var has_avatar = false;
  11429.     var has_email = false;
  11430.     var mains = new Array();
  11431.     var mutuals = new Array();
  11432.     var emails = new Array();
  11433.     var virgin_avatar_mutuals = new Array();
  11434.     var virgin_avatarless_mutuals = new Array();
  11435.     var virgin_gmails = new Array();
  11436.     var virgin_emails = new Array();
  11437.     
  11438.     var contacts = su_ds.selectAllRows("contact");
  11439.     var i;
  11440.     
  11441.     if (! contacts)
  11442.         return;
  11443.     
  11444.     for (i = 0; i < contacts.length; i++)
  11445.     {
  11446.         var send_obj;
  11447.         if (contacts[i].mutual)
  11448.         {
  11449.             send_obj = new su_SendObj("friend", contacts[i]);
  11450.             mutuals.push(send_obj);
  11451.             
  11452.             if (send_obj.count)
  11453.             {
  11454.                 has_avatar = (has_avatar || (send_obj.avatar_url != ""));
  11455.                 mains.push(send_obj);
  11456.             }
  11457.             else if (send_obj.avatar_url == "")
  11458.             {
  11459.                 virgin_avatarless_mutuals.push(send_obj);
  11460.             }
  11461.             else
  11462.             {
  11463.                 virgin_avatar_mutuals.push(send_obj);
  11464.             }
  11465.         }
  11466.         else if (contacts[i].email && (! contacts[i].hidden))
  11467.         {
  11468.             send_obj = new su_SendObj("email", contacts[i]);
  11469.             emails.push(send_obj);
  11470.             
  11471.             if (send_obj.count)
  11472.             {
  11473.                 has_email = true;
  11474.                 mains.push(send_obj);
  11475.             }
  11476.             else if (send_obj.compare_name.indexOf("@gmail.com") != -1)
  11477.             {
  11478.                 virgin_gmails.push(send_obj);
  11479.             }
  11480.             else
  11481.             {
  11482.                 virgin_emails.push(send_obj);
  11483.             }
  11484.         }
  11485.     }
  11486.     
  11487.     emails.sort(function (a, b)
  11488.                 {
  11489.                     if ( a.compare_name > b.compare_name ) return 1;
  11490.                     if ( a.compare_name < b.compare_name ) return -1;
  11491.                     return 0;
  11492.                 });
  11493.         
  11494.     mutuals.sort(function (a, b)
  11495.                 {
  11496.                     if ( a.compare_name > b.compare_name ) return 1;
  11497.                     if ( a.compare_name < b.compare_name ) return -1;
  11498.                     return 0;
  11499.                 });
  11500.     
  11501.     var sendtos_count_max = su_ds.getValue("$sendtos_menu_depth");
  11502.     
  11503.     if (mains.length > sendtos_count_max)
  11504.     {
  11505.         // Add and populate the Recent submenu. -- JW
  11506.         mains.sort(function (a, b)
  11507.                     {
  11508.                         if ( a.timestamp < b.timestamp ) return 1;
  11509.                         if ( a.timestamp > b.timestamp ) return -1;
  11510.                         return 0;
  11511.                     });
  11512.         
  11513.         menu = document.createElement("menu");
  11514.         menu.setAttribute("label", "Recent");
  11515.         menu.setAttribute("tooltiptext", "Recent recipients");
  11516.         referral_popup.appendChild(menu);
  11517.         popup = document.createElement("menupopup");
  11518.         menu.appendChild(popup);
  11519.  
  11520.         var recent_count_max = su_ds.getValue("$recent_sendtos_menu_depth");
  11521.         for (i = 0; (i < mains.length) && (i < recent_count_max); i++)
  11522.         {
  11523.             ja = document.createElement("menuitem");
  11524.             ja.setAttribute("label", mains[i].name + " (" + mains[i].count + ")");
  11525.             ja.setAttribute("oncommand", "su_sendto(\"" + mains[i].name + "\");");
  11526.             ja.setAttribute("tooltiptext", "Send to " + mains[i].name);
  11527.             popup.appendChild(ja);
  11528.         }
  11529.         
  11530.         // separator
  11531.         ja = document.createElement("menuseparator");
  11532.         referral_popup.appendChild(ja);
  11533.     }
  11534.  
  11535.     virgin_avatar_mutuals.sort(function (a, b)
  11536.                 {
  11537.                     return ((Math.random() > 0.5) ? 1 : -1);
  11538.                 });
  11539.     
  11540.     virgin_avatarless_mutuals.sort(function (a, b)
  11541.                 {
  11542.                     return ((Math.random() > 0.5) ? 1 : -1);
  11543.                 });
  11544.     
  11545.     virgin_gmails.sort(function (a, b)
  11546.                 {
  11547.                     return ((Math.random() > 0.5) ? 1 : -1);
  11548.                 });
  11549.     
  11550.     virgin_emails.sort(function (a, b)
  11551.                 {
  11552.                     return ((Math.random() > 0.5) ? 1 : -1);
  11553.                 });
  11554.     
  11555.     var gmail_quota = (sendtos_count_max - (mains.length + 
  11556.                 virgin_avatar_mutuals.length + 
  11557.                 virgin_avatarless_mutuals.length)) * 0.5;
  11558.     
  11559.     var gmail_quota_i = 0;
  11560.     
  11561.     while ((mains.length < sendtos_count_max) && 
  11562.                 ((virgin_avatar_mutuals.length > 0) ||
  11563.                 (virgin_avatarless_mutuals.length > 0) ||
  11564.                 (virgin_gmails.length > 0) ||
  11565.                 (virgin_emails.length > 0)))
  11566.     {
  11567.         if (virgin_avatar_mutuals.length > 0)
  11568.         {
  11569.             mains.push(virgin_avatar_mutuals.shift());
  11570.             has_avatar = true;
  11571.         }
  11572.         else if (virgin_avatarless_mutuals.length > 0)
  11573.         {
  11574.             mains.push(virgin_avatarless_mutuals.shift());
  11575.         }
  11576.         else if ((gmail_quota_i < gmail_quota) && (virgin_gmails.length > 0))
  11577.         {
  11578.             mains.push(virgin_gmails.shift());
  11579.             gmail_quota_i++;
  11580.             has_email = true;
  11581.         }
  11582.         else if (virgin_emails.length > 0)
  11583.         {
  11584.             mains.push(virgin_emails.shift());
  11585.             has_email = true;
  11586.         }
  11587.         else
  11588.         {
  11589.             mains.push(virgin_gmails.shift());
  11590.             has_email = true;
  11591.         }
  11592.     }
  11593.     
  11594.     // Sort the main Share menu by decreasing count and increasing
  11595.     // name. -- JW
  11596.     mains.sort(function (a, b)
  11597.                 {
  11598.                     if ( a.count < b.count ) return 1;
  11599.                     if ( a.count > b.count ) return -1;
  11600.                     if ( a.compare_name > b.compare_name ) return 1;
  11601.                     if ( a.compare_name < b.compare_name ) return -1;
  11602.                     return 0;
  11603.                 });
  11604.  
  11605.     var abbr_send_array = new Array();
  11606.     var abbr_work_array = new Array();
  11607.     var max_abbr_idx = 0;
  11608.     for (i = 0; (i < mains.length) && (i < sendtos_count_max); i++)
  11609.     {
  11610.         // Build the abbr_send_array, and begin calcuating e-mail 
  11611.         // abbreviations. -- JW
  11612.         var item = mains[i];
  11613.         var at_idx = item.name.indexOf("@");
  11614.         if (at_idx == -1)
  11615.         {
  11616.             item.abbr_idx = item.name.length - 1;
  11617.             if (item.abbr_idx > max_abbr_idx)
  11618.             {
  11619.                 max_abbr_idx = item.abbr_idx;
  11620.             }
  11621.         }
  11622.         else if (at_idx <= 14)
  11623.         {
  11624.             item.abbr_idx = su_truncate_at(item.name, 14);
  11625.             abbr_work_array.push(item);
  11626.         }
  11627.         else
  11628.         {
  11629.             item.abbr_idx = at_idx;
  11630.             abbr_work_array.push(item);
  11631.         }
  11632.         abbr_send_array.push(item);
  11633.     }        
  11634.     
  11635.     var j;
  11636.     var item_a, item_b;
  11637.     for (i = 0; i < abbr_work_array.length; i++)
  11638.     {
  11639.         // Eliminate duplicate e-mail abbreviations. -- JW
  11640.         item_a = abbr_work_array[i];
  11641.         for (j = i + 1; j < abbr_work_array.length; j++)
  11642.         {
  11643.             item_b = abbr_work_array[j];
  11644.             
  11645.             var common_idx = (item_a.abbr_idx > item_b.abbr_idx) ? item_b.abbr_idx : item_a.abbr_idx;
  11646.  
  11647.             if (common_idx > 3)
  11648.                 common_idx -= 2;
  11649.             
  11650.             while ((item_a.name.substring(0, common_idx + 1) == item_b.name.substring(0, common_idx + 1)) && (common_idx <= item_a.name.length) && (common_idx <= item_b.name.length))
  11651.                 common_idx++;
  11652.             
  11653.             item_a.abbr_idx = (common_idx > item_a.abbr_idx) ? common_idx : item_a.abbr_idx;
  11654.             item_a.abbr_idx = su_truncate_at(item_a.name, item_a.abbr_idx);
  11655.             item_b.abbr_idx = (common_idx > item_b.abbr_idx) ? common_idx : item_b.abbr_idx;
  11656.             item_b.abbr_idx = su_truncate_at(item_b.name, item_b.abbr_idx);
  11657.         }
  11658.  
  11659.         if (item_a.abbr_idx > max_abbr_idx)
  11660.             max_abbr_idx = item_a.abbr_idx
  11661.     }
  11662.     
  11663.     // If twitter or fb are supr linked, then add the link at the top.
  11664.     var twitter_facebook_ontop = su_ds.getValue("$twitter_supr_linked") || su_ds.getValue("$facebook_supr_linked");
  11665.     if (twitter_facebook_ontop)
  11666.     {
  11667.         su_append_twitter_facebook_menuitem(referral_popup, has_avatar);
  11668.     }
  11669.  
  11670.     if (abbr_send_array.length > 0)
  11671.     {
  11672.         // Populate the main Share menu. -- JW
  11673.         
  11674.         var item_count_max = su_ds.getValue("$sendtos_menu_depth");
  11675.         for (i = 0; i < abbr_send_array.length; i++)
  11676.         {
  11677.             var item = abbr_send_array[i];
  11678.             ja = document.createElement("menuitem");
  11679.             var label;
  11680.             if (item.abbr_idx == item.name.length - 1)
  11681.                 label = item.name;
  11682.             else
  11683.                 label = item.name.substring(0, item.abbr_idx + ((item.count == 0) ? 4 : 1)) + "...";
  11684.  
  11685.             if (item.count > 0)
  11686.                 label += " (" + item.count + ")";
  11687.             
  11688.             ja.setAttribute("label", label);
  11689.             ja.setAttribute("tooltiptext", "Send to " + item.name);
  11690.             if (item.type == "friend")
  11691.             {
  11692.                 ja.setAttribute("oncommand", "su_sendto(\"" + item.name + "\");");
  11693.                 if (item.avatar_url == "")
  11694.                 {
  11695.                     if (has_email)
  11696.                     {
  11697.                         ja.setAttribute("image", "chrome://stumbleupon/content/skin/greyman.png");
  11698.                         if (has_avatar) //!!! create larger image
  11699.                             ja.setAttribute("class", "menuitem-iconic su-iconic-referral");
  11700.                         else
  11701.                             ja.setAttribute("class", "menuitem-iconic");
  11702.                     }
  11703.                 }
  11704.                 else
  11705.                 {
  11706.                     ja.setAttribute("image", item.avatar_url);
  11707.                     ja.setAttribute("class", "menuitem-iconic su-iconic-referral");
  11708.                 }
  11709.             }
  11710.             else if (item.type == "email")
  11711.             {
  11712.                 ja.setAttribute("oncommand", "su_mailit(\"" + item.name + "\");");
  11713.                 if (has_avatar) //!!! create larger image
  11714.                 {
  11715.                     ja.setAttribute("image", "chrome://stumbleupon/content/skin/arrow.png");
  11716.                     ja.setAttribute("class", "menuitem-iconic su-iconic-referral");
  11717.                 }
  11718.             }
  11719.             referral_popup.appendChild(ja);
  11720.         }
  11721.     }
  11722.     
  11723.     // If twitter or fb are not supr linked, then add the link to the bottom.
  11724.     if (!twitter_facebook_ontop)
  11725.     {
  11726.         su_append_twitter_facebook_menuitem(referral_popup, has_avatar);
  11727.     }
  11728.     
  11729.     ja = document.createElement("menuseparator");
  11730.     referral_popup.appendChild(ja);
  11731.  
  11732.     if (mutuals.length > 0)
  11733.     {
  11734.         menu = document.createElement("menu");
  11735.         menu.setAttribute("label", "Stumblers");
  11736.         menu.setAttribute("tooltiptext", "All of the stumblers you can share with");
  11737.         referral_popup.appendChild(menu);
  11738.         
  11739.         popup = document.createElement("menupopup");
  11740.         menu.appendChild(popup);
  11741.         
  11742.         for (i = 0; i < mutuals.length; i++)
  11743.         {
  11744.             ja = document.createElement("menuitem");
  11745.             if (mutuals[i].count)
  11746.                 ja.setAttribute("label", mutuals[i].name + " (" + mutuals[i].count + ")");
  11747.             else
  11748.                 ja.setAttribute("label", mutuals[i].name);
  11749.     
  11750.             ja.setAttribute("oncommand", "su_sendto(\"" + mutuals[i].name + "\");");
  11751.             ja.setAttribute("tooltiptext", "Send to " + mutuals[i].name);
  11752.             popup.appendChild(ja);
  11753.         }
  11754.     }
  11755.         
  11756.     if (emails.length > 0)
  11757.     {
  11758.         menu = document.createElement("menu");
  11759.         menu.setAttribute("label", "All Emails");
  11760.         menu.setAttribute("tooltiptext", "All email addresses");
  11761.         referral_popup.appendChild(menu);
  11762.  
  11763.         popup = document.createElement("menupopup");
  11764.         menu.appendChild(popup);
  11765.         
  11766.         menu = document.createElement("menu");
  11767.         menu.setAttribute("label", "Remove Email");
  11768.         menu.setAttribute("tooltiptext", "Remove an email address");
  11769.         popup.appendChild(menu);
  11770.         
  11771.         var remove_popup = document.createElement("menupopup");
  11772.         menu.appendChild(remove_popup);
  11773.         
  11774.         ja = document.createElement("menuseparator");
  11775.         popup.appendChild(ja);
  11776.         
  11777.         for (i = 0; i < emails.length; i++)
  11778.         {
  11779.             var name = emails[i].name;
  11780.             ja = document.createElement("menuitem");
  11781.             if (emails[i].count)
  11782.                 ja.setAttribute("label", name + " (" + emails[i].count + ")");
  11783.             else
  11784.                 ja.setAttribute("label", name);
  11785.     
  11786.             ja.setAttribute("tooltiptext", "Send to " + name);
  11787.             ja.setAttribute("oncommand", "su_mailit(\"" + name + "\");");
  11788.             popup.appendChild(ja);
  11789.             
  11790.             ja = document.createElement("menuitem");
  11791.             ja.setAttribute("label", name);
  11792.             ja.setAttribute("oncommand", "su_remove_email(\"" + name + "\");");
  11793.             ja.setAttribute("tooltiptext", "Remove this address");
  11794.             remove_popup.appendChild(ja);
  11795.         }
  11796.     }
  11797.     
  11798.     ja = document.createElement("menuitem");
  11799.     ja.setAttribute("label", "New Email Address...");
  11800.     ja.setAttribute("image", "chrome://stumbleupon/content/skin/arrow.png");
  11801.     ja.setAttribute("class", "menuitem-iconic");
  11802.     ja.setAttribute("tooltiptext", "Send to a new e-mail address");
  11803.     ja.setAttribute("oncommand", 'su_mailit("");');
  11804.     referral_popup.appendChild(ja);
  11805.  
  11806.     ja = document.createElement("menuseparator");
  11807.     referral_popup.appendChild(ja);
  11808.  
  11809.     ja = document.createElement("menuitem");
  11810.     ja.setAttribute("label", "Find people you know...");
  11811.     ja.setAttribute("class", "menuitem-iconic");
  11812.     ja.setAttribute("image", "chrome://stumbleupon/content/skin/friend.png");
  11813.     ja.setAttribute("tooltiptext", "Import contacts from an address book");
  11814.     ja.setAttribute("onclick", "su_invite(event);");
  11815.     
  11816.     referral_popup.appendChild(ja);
  11817.     
  11818.     
  11819.     } catch (e) { su_log_error("REFERRAL MENU", e); }
  11820. }
  11821.  
  11822. // utility function for update_referral_menu()
  11823. function su_truncate_at(str, idx)
  11824. {
  11825.     if (str.length < idx + 6)
  11826.         idx = str.length - 1;
  11827.     
  11828.     return idx;
  11829. }
  11830.  
  11831. // This function grabs urls from recommend.php and stores them in stumbleurls (user_cat is either category id of incat stumble or 0)
  11832. function su_update_url_cache(user_cat, check_referral, callback, context)
  11833. {
  11834.     try {
  11835.     
  11836.     var res;
  11837.     var postspec = new Object();
  11838.     var now = su_get_time_s();
  11839.     
  11840.     if (context.first_of_day)
  11841.         postspec.first_of_day = 1;
  11842.     
  11843.     postspec.houroffset = Math.floor((new Date()).getTimezoneOffset() / 60);
  11844.     
  11845.     if (su_isInt(user_cat))
  11846.     {
  11847.         postspec.category = user_cat;
  11848.     }
  11849.     else
  11850.     {
  11851.         if (user_cat.indexOf("LANG_") == 0)
  11852.         {
  11853.             postspec.language = user_cat.substr(5);
  11854.         }
  11855.         else if (user_cat.indexOf("TAG_") == 0)
  11856.         {
  11857.             postspec.tag = user_cat.substr(4);
  11858.         }
  11859.         else if (user_cat.indexOf("USERTAG_") == 0)
  11860.         {
  11861.             var chunk = user_cat.substr(8);
  11862.             chunks = chunk.split('_');
  11863.             var tag = chunks[1];
  11864.             var profile = chunks[0];
  11865.             postspec.showfriend = profile;
  11866.             postspec.tag = tag;
  11867.         }
  11868.         else
  11869.         {
  11870.             if (user_cat == "news")
  11871.                 postspec.shownews = 1;
  11872.             
  11873.             else if (user_cat == "video")
  11874.                 postspec.mode = "video";
  11875.             
  11876.             else if (user_cat == "friends")
  11877.                 postspec.mode = "friends";
  11878.             
  11879.             else if (user_cat == "wiki")
  11880.                 postspec.mode = "wiki";
  11881.             
  11882.             else    
  11883.                 postspec.showfriend = user_cat;
  11884.         }
  11885.     }
  11886.     
  11887.     if (check_referral)
  11888.         postspec.check_referral = 1;
  11889.     
  11890.     // if we need to upload_stumbles, do it
  11891.     if (su_ds.getValue("$stumblestats") != "")
  11892.     {
  11893.         postspec.urlids = su_ds.getValue("$stumblestats");
  11894.         postspec.timestamps = su_ds.getValue("$stumbletimes");
  11895.         postspec.types = su_ds.getValue("$stumbletypes");
  11896.         postspec.referralids = su_ds.getValue("$stumblereferrals");
  11897.         postspec.clienttime = now;
  11898.         context.oldStumbleReport = true;
  11899.     }
  11900.     
  11901.     postspec.recentlyseen = su_ds.getValue("$recently_seen");
  11902.     postspec.recentlyseen_publicids = su_ds.getValue("$recently_seen_publicids");
  11903.     postspec.recentlyseen_referralids = su_ds.getValue("$recently_seen_referralids");
  11904.     
  11905.     var params = su_build_request_param_string(postspec);
  11906.     
  11907.     params = su_append_sync_params(params);
  11908.     
  11909.     if (callback)
  11910.         context.callbacks.push(callback);
  11911.     
  11912.     context.dd_uc_server = su_servername;
  11913.     context.check_referral = check_referral;
  11914.  
  11915.     su_post_url_server_async(
  11916.                 "recommend.php",
  11917.                 params,
  11918.                 su_ds.getValue("@recommend_timeout_ms"),
  11919.                 su_update_url_cache_done,
  11920.                 context);
  11921.     
  11922.     } catch (e) { su_log_error("RECOMMEND BEGIN", e); }
  11923. }
  11924.  
  11925. function su_update_url_cache_done(res)
  11926. {
  11927.     try {
  11928.     
  11929.     var context = res.detail;
  11930.     var callback = null;
  11931.     var ancestor_callback = null;
  11932.     if (context)
  11933.     {
  11934.         callback = context.callbacks.pop();
  11935.         ancestor_callback = context.callbacks.pop();
  11936.     }
  11937.  
  11938.     if (res.aborted)
  11939.     {
  11940.         if (callback)
  11941.             callback("error", ancestor_callback, context);
  11942.         return;
  11943.     }
  11944.  
  11945.     try {
  11946.         if (res.status == 1)
  11947.         {
  11948.             if (callback)
  11949.                 callback("error", ancestor_callback, context);
  11950.             return;
  11951.         }
  11952.     } catch (e) {}
  11953.  
  11954.     try {
  11955.         if (res.status != 200)
  11956.         {
  11957.             // Maintenance mode returns 503 with "ERROR xxx" set.
  11958.             // In that case, let the "ERROR" command be handled.
  11959.             var isMaintenanceMode = false;
  11960.             if(res.status == 503)
  11961.             {
  11962.                 var commands = res.responseText.split(" ");
  11963.                 if(commands.length && (commands[0] == "ERROR"))
  11964.                 {
  11965.                     // Let it fall through 
  11966.                     isMaintenanceMode = true;
  11967.                 }
  11968.             }
  11969.             if(!isMaintenanceMode)
  11970.             {
  11971.                 if (! context.quiet)
  11972.                     alert("The stumbleupon.com server is currently down.\nPlease try again, and if you are still having difficulties,\ngo to "
  11973.                         + su_base_url + "feedback.php to report the problem\nError : " + res.error + "\nStatus : " + res.status);
  11974.                 if (callback)
  11975.                     callback("connection error", ancestor_callback, context);
  11976.                 return;
  11977.             }
  11978.         }
  11979.     }
  11980.     catch (e) {
  11981.         if (! context.quiet)
  11982.             alert("The stumbleupon.com server is currently down.\nPlease try again, and if you are still having difficulties,\ngo to "
  11983.                 + su_base_url + "feedback.php to report the problem.\nError : connection error");
  11984.         if (callback)
  11985.             callback("connection error", ancestor_callback, context);
  11986.     }
  11987.     
  11988.     var s = "";
  11989.     if (typeof(res.responseText) != "undefined")
  11990.         s = res.responseText;
  11991.     
  11992.     if (su_log_communication && ((! context.quiet) || su_log_polling))
  11993.         su_log("response recommend.php", s);
  11994.     
  11995.     // Parse response text
  11996.     var parsed = s.split("\n");
  11997.     
  11998.     var undelivered_count = 0;
  11999.  
  12000.     var pre_stumbles = new Array(); // temporary variable for storing stumbles if we are checking referrals
  12001.  
  12002.     // Iterate through commands
  12003.     var i;
  12004.     for (i = 0; i < parsed.length; i++)
  12005.     {
  12006.         if (parsed[i] == "")
  12007.             continue;
  12008.  
  12009.         // Parse command structure
  12010.         var command = parsed[i].split(" ");
  12011.         if (command[0] == "")
  12012.             continue;
  12013.         
  12014.         switch(command[0])
  12015.         {
  12016.             case "ERROR":
  12017.                 if (command[1] == "INCORRECT_PASSWORD" && context.quiet)
  12018.                 {
  12019.                     // auth failed during polling, so poll less frequently
  12020.                     
  12021.                     // note that iebar signs out when it receives INCORRECT_PASSWORD
  12022.                     
  12023.                     su_invoke_global_event("logout", null)
  12024.                     return;
  12025.                 }
  12026.                 else if (command[1] == "NO_INTERESTS")
  12027.                 {
  12028.                     // Redirect to interests page
  12029.                     var loc = su_serverhttp + "interests.php";
  12030.                     //!!! disabled because it screws up history
  12031.                     // if (su_get_browser_url() != loc)
  12032.  
  12033.                     getBrowser().contentDocument.location = loc;
  12034.  
  12035.                     if (callback)
  12036.                         callback("error", ancestor_callback, context);
  12037.                     return;
  12038.                 }
  12039.                 else if (command[1] == "NO_SITES")
  12040.                 {
  12041.                     // do nothing
  12042.                 }
  12043.                 else
  12044.                 {
  12045.                     if (! context.quiet)
  12046.                         su_handle_error(command[1]);
  12047.                     
  12048.                     if (callback)
  12049.                         callback("error", ancestor_callback, context);
  12050.                     return;
  12051.                 }
  12052.                 break;
  12053.             case "URL":
  12054.                 pre_stumbles.push(parsed[i].substr(4));
  12055.                 // Check to see if we have a referral
  12056.                 if (typeof(command[8]) != "undefined" && command[8] == 4)
  12057.                     undelivered_count++;
  12058.                 break;
  12059.             default:
  12060.                 su_process_command(parsed[i], context, command);
  12061.                 break;
  12062.         }
  12063.     }
  12064.     su_ds.flushPrefs();
  12065.  
  12066.     // save referral count
  12067.  
  12068.     if (context.user_cat == 0)
  12069.         su_ds.setValue("$undelivered_count", undelivered_count);
  12070.  
  12071.     // might as well clear old stumbles, they are old
  12072.     // and there really should only be 1 of them anyway
  12073.     if (!(context.check_referral && undelivered_count == 0))
  12074.     {
  12075.         clear_stumbles();
  12076.     }
  12077.     
  12078.     su_update_referred(false);
  12079.     
  12080.     // populate the stumbles array
  12081.     su_load_stumbles(null);
  12082.     
  12083.     // dump the new stumbles onto the end of stumbles
  12084.     for (i = 0; i < pre_stumbles.length; i++)
  12085.         stumbles.push(pre_stumbles[i]);
  12086.     
  12087.     // Now dump the new stumble queue to disk
  12088.     su_save_stumbles();
  12089.     
  12090.     if (stumbles.length && (su_ds.lookup("userid:uc_logger_flag", stumbleid) ||
  12091.                 su_ds.getValue("@dd_uc")))
  12092.         su_ds.setValue("@dd_uc_server", context.dd_uc_server);
  12093.     
  12094.     if (callback)
  12095.         callback("", ancestor_callback, context);
  12096.     
  12097.     } catch (e) { su_log_error("RECOMMEND DONE", e); }
  12098. }
  12099.  
  12100. function su_update_referred(disable_animation)
  12101. {
  12102.     setTimeout(su_update_referred2, 0, disable_animation);
  12103. }
  12104.  
  12105. function su_update_referred2(disable_animation)
  12106. {
  12107.     var undelivered_count = su_ds.getValue("$undelivered_count"); 
  12108.     
  12109.     su_set_label("su_referred", undelivered_count);
  12110.     
  12111.     if (su_get_element("su_referred").disabled)
  12112.         return;
  12113.     
  12114.     if (undelivered_count > 0)
  12115.     {
  12116.         su_register_activity("referred");
  12117.         if (! disable_animation)
  12118.             su_set_attribute("su_referred", "busy", "true");
  12119.         su_set_visible("su_referred", true);
  12120.      }
  12121.     else
  12122.     {
  12123.         su_set_visible("su_referred", false);
  12124.     }
  12125. }
  12126.     
  12127. function su_save_stumbles()
  12128. {
  12129.     var towrite = "";
  12130.     for (var ii = 0; ii < stumbles.length; ii++)
  12131.         towrite += stumbles[ii] + "\n";
  12132.     
  12133.     su_write_file_user("stumbleurls", towrite);
  12134. }
  12135.  
  12136. // Saves a rating to the rating history (so we can grey out rating buttons later)
  12137. function su_store_rating(u, c)
  12138. {
  12139.     var url_detail = su_ds.lookup("url:url_detail", u)
  12140.     if (url_detail)
  12141.         url_detail.rating = c;
  12142.     
  12143.     // Load rating history (in case the user has rated something in another window)
  12144.     stumblecat = su_read_file_user("stumblerating");
  12145.     splitcat = stumblecat.split("\n");
  12146.     for (var i = 0; i < splitcat.length; i++)
  12147.     {
  12148.         if (splitcat[i] == "")
  12149.             continue;
  12150.         split2 = splitcat[i].split(" ");
  12151.         su_ratings[split2[0]] = split2[1];
  12152.     }
  12153.  
  12154.     // Add the new rating
  12155.     su_ratings[u] = c;
  12156.  
  12157.     // Now dump it to disk
  12158.     var towrite = "";
  12159.     for (var ii in su_ratings)
  12160.     {
  12161.         if (su_is_property_garbage(su_ratings, ii))
  12162.             continue;
  12163.         
  12164.         towrite += ii + " " + su_ratings[ii] + "\n";
  12165.     }
  12166.     su_write_file_user("stumblerating", towrite); 
  12167. }
  12168.  
  12169. function su_delete_rating(u)
  12170. {
  12171.     var url_detail = su_ds.lookup("url:url_detail", u)
  12172.     if (url_detail)
  12173.         url_detail.rating = null;
  12174.  
  12175.     // Load rating history (in case the user has rated something in another window)
  12176.     stumblecat = su_read_file_user("stumblerating");
  12177.     splitcat = stumblecat.split("\n");
  12178.     su_ratings = new Array();
  12179.     for (var i = 0; i < splitcat.length; i++)
  12180.     {
  12181.         if (splitcat[i] == "")
  12182.             continue;
  12183.         split2 = splitcat[i].split(" ");
  12184.         if (split2[0] != u)
  12185.             su_ratings[split2[0]] = split2[1];
  12186.     }
  12187.  
  12188.     // Now dump it to disk
  12189.     var towrite = "";
  12190.     for (var ii in su_ratings)
  12191.     {
  12192.         if (su_is_property_garbage(su_ratings, ii))
  12193.             continue;
  12194.         
  12195.         towrite += ii + " " + su_ratings[ii] + "\n";
  12196.     }
  12197.     su_write_file_user("stumblerating", towrite); 
  12198. }
  12199.  
  12200. // performs a synchronous POST, when the interface is beneath the www
  12201. // stumbleupon domain
  12202. function su_post_url_server(uri_suffix, postdata)
  12203. {
  12204.     return su_post_url(
  12205.                 su_serverhttp + uri_suffix + "?username=" + stumbleid,
  12206.                 postdata);
  12207. }
  12208.  
  12209. function su_post_url_server_secure(uri_suffix, postdata)
  12210. {
  12211.     return su_post_url(
  12212.                 su_serverhttps + uri_suffix + "?username=" + stumbleid,
  12213.                 postdata);
  12214. }
  12215.  
  12216. // performs a synchronous POST
  12217. function su_post_url(uri, postdata)
  12218. {
  12219.     var script_timeout_saved;
  12220.      try {
  12221.         if (su_ds.isPrefDefined("dom.max_chrome_script_run_time"))
  12222.         {
  12223.             script_timeout_saved = su_ds.getValue("dom.max_chrome_script_run_time");
  12224.             su_ds.setValue("dom.max_chrome_script_run_time", 120);
  12225.         }
  12226.     } catch (e) {}
  12227.     
  12228.     // This function trys to post 3 times (since there is 
  12229.     // something screwy with xmlhttprequest).
  12230.     var ret2 = new Object();
  12231.     var x;
  12232.     var status;
  12233.     var retries = 3;
  12234.  
  12235.     if (! postdata)
  12236.         postdata = "";
  12237.     
  12238.     var client_postdata = su_get_client_postdata(uri);
  12239.     if (client_postdata != "")
  12240.         postdata += ((postdata == "") ? "" : "&") + client_postdata;
  12241.     
  12242.     for (var i = 1; i <= retries; i++)
  12243.     {
  12244.         x = new XMLHttpRequest();
  12245.         netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
  12246.         x.open("POST", uri, false);
  12247. //        x.setRequestHeader("User-Agent" , su_useragent); // unnecessary since we set X-SU-Version
  12248.         x.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  12249.         try { 
  12250.             if (su_log_communication && (uri.indexOf("topics.csv") == -1))
  12251.                 su_log("post sync", uri, postdata, "attempt: " + i);
  12252.             x.send(postdata); 
  12253.             status = x.status;
  12254.             break;
  12255.         }
  12256.         catch (e) {
  12257.             if (i == retries) 
  12258.             {
  12259.                 // Failed on 3nd try, bail out
  12260.                 ret2.error = e;
  12261.                 ret2.response = "";
  12262.                 ret2.status = 1;
  12263.                 try {
  12264.                     if (su_ds.isPrefDefined("dom.max_chrome_script_run_time"))
  12265.                     {
  12266.                         su_ds.setValue(
  12267.                                     "dom.max_chrome_script_run_time",
  12268.                                     script_timeout_saved);
  12269.                     }
  12270.                 } catch (e) {}
  12271.                 return ret2;
  12272.             }
  12273.         }
  12274.     }
  12275.     ret2.error = "";
  12276.     ret2.response = x.responseText;
  12277.     if (typeof(ret2.response) == "undefined")
  12278.         ret2.response = "";
  12279.     ret2.status = x.status;
  12280.     var mime = '';
  12281.     try {
  12282.         mime = x.getResponseHeader("Content-Type");
  12283.     }
  12284.     catch (e) {
  12285.         mime = '';
  12286.     }
  12287.     
  12288.     if (mime != null && typeof(mime) != "undefined" && mime != '')
  12289.     {
  12290.         var mimes = mime.split(";");
  12291.         ret2.mimetype    = mimes[0];
  12292.     }
  12293.     else
  12294.         ret2.mimetype = '';
  12295.     try {
  12296.         if (su_ds.isPrefDefined("dom.max_chrome_script_run_time"))
  12297.         {
  12298.             su_ds.setValue(
  12299.                         "dom.max_chrome_script_run_time",
  12300.                         script_timeout_saved);
  12301.         }
  12302.     } catch (e) {}
  12303.     return ret2;
  12304. }
  12305.  
  12306. // begins an asynchronous POST, when the interface is beneath the www
  12307. // stumbleupon domain
  12308. function su_post_url_server_async(uri_suffix, postdata, timeout_interval_ms, callback, detail)
  12309. {
  12310.     if (! detail)
  12311.         detail = new Object();
  12312.     detail.request_target = uri_suffix;
  12313.     
  12314.     su_post_url_async(
  12315.                 su_serverhttp + uri_suffix + 
  12316.                     ((stumbleid && (uri_suffix != "stumblethru.csv")) ? 
  12317.                     ("?username=" + stumbleid) : ""),
  12318.                 postdata,
  12319.                 timeout_interval_ms,
  12320.                 callback,
  12321.                 detail);
  12322. }
  12323.  
  12324. function su_post_url_server_async_secure(uri_suffix, postdata, timeout_interval_ms, callback, detail)
  12325. {
  12326.     if (! detail)
  12327.         detail = new Object();
  12328.     detail.request_target = uri_suffix;
  12329.     
  12330.     su_post_url_async(
  12331.                 su_serverhttps + uri_suffix + 
  12332.                     ((stumbleid && (uri_suffix != "stumblethru.csv")) ? 
  12333.                     ("?username=" + stumbleid) : ""),
  12334.                 postdata,
  12335.                 timeout_interval_ms,
  12336.                 callback,
  12337.                 detail);
  12338. }
  12339.  
  12340. // begins an asynchronous POST
  12341. function su_post_url_async(uri, postdata, timeout_interval_ms, callback, detail)
  12342. {
  12343.     // This ensures that our request objects are created in the context
  12344.     // of this window.  This is necessary for the first stumble after
  12345.     // new account creation. -- JW
  12346.     setTimeout(function (window, uri, postdata, timeout_interval_ms, callback, detail) { window.su_post_url_async_wrapped(uri, postdata, timeout_interval_ms, callback, detail); }, 0, window, uri, postdata, timeout_interval_ms, callback, detail);
  12347. }
  12348.  
  12349. // do not call this; call post_url_async instead
  12350. function su_post_url_async_wrapped(uri, postdata, timeout_interval_ms, callback, detail)
  12351. {
  12352.     if (! postdata)
  12353.         postdata = "";
  12354.     
  12355.     postdata += ((postdata == "") ? "" : "&") + su_get_client_postdata(uri);
  12356.     
  12357.     su_service.postAsync(su_useragent, uri, postdata, timeout_interval_ms, callback, detail);
  12358. }
  12359.  
  12360. // Used by post_url, post_url_async and stumble_done to
  12361. // construct version and authentication portions of postdata
  12362. function su_get_client_postdata(uri)
  12363. {
  12364.     var postdata = "";
  12365.     
  12366.     if (uri.indexOf(su_serverhttp) == 0)
  12367.         postdata += "version=" + su_verstring;
  12368.  
  12369.     if (su_is_auth_allowed(uri))
  12370.     {
  12371.         if (su_enable_hashed_password)
  12372.         {
  12373.             postdata += ((postdata == "") ? "" : "&") + 
  12374.                         "username=" + stumbleid + 
  12375.                         "&password=" + stumblepass +
  12376.                         "&ycc=" + su_ds.getCC();
  12377.         }
  12378.         else
  12379.         {
  12380.             postdata += ((postdata == "") ? "" : "&") + 
  12381.                         "username=" + stumbleid + 
  12382.                         "&password=" + encodeURIComponent(stumblepass) +
  12383.                         "&ycc=" + su_ds.getCC();
  12384.         }
  12385.     }
  12386.     return postdata;
  12387. }
  12388.  
  12389. // used by the http_observer and get_client_postdata to determine
  12390. // whether we're allowed to send authentication to the page
  12391. function su_is_auth_allowed(url)
  12392. {
  12393.     if (! su_is_matching_domain(url, su_servername))
  12394.         return false;
  12395.     
  12396.     if ((url.indexOf(su_serverhttp == 0)) || (url.indexOf(su_serverhttps == 0)))
  12397.     {
  12398.         // These get special authentication sent in postdata.
  12399.         if ((su_is_server_page(url, "userexists.php")) ||
  12400.                     (su_is_server_page(url, "delete_account.php")) ||
  12401.                     (su_is_server_page(url, "change_password.php")) ||
  12402.                     (su_is_server_page(url, "sign_up.php")) ||
  12403.                     (su_is_server_page(url, "getid.php")) ||
  12404.                     (su_is_server_page(url, "init_user.php")) ||
  12405.                     (su_is_server_page(url, "signup.php")))
  12406.             return false;
  12407.  
  12408.         // Don't bother with obvious non-pages....
  12409.         if ((su_is_server_page(url, "images/")) ||
  12410.                     (su_is_server_page(url, "pics/")) ||
  12411.                     (su_is_server_page(url, "iconpics/")) ||
  12412.                     (su_is_server_page(url, "superminipics/")) ||
  12413.                     (su_is_server_page(url, "groupsuperminipics/")) ||
  12414.                     (su_is_server_page(url, "topicsuperminipics/")) ||
  12415.                     (su_is_server_page(url, "mediumpics/")) ||
  12416.                     (su_is_server_page(url, "thumb/")) ||
  12417.                     (su_is_server_page(url, "css/")) ||
  12418.                     (su_is_server_page(url, "js/")) ||
  12419.                     (su_is_server_page(url, "favicon.ico")) ||
  12420.                     (su_is_server_page(url, "stumble.js")) ||
  12421.                     (su_is_server_page(url, "post.js")) ||
  12422.                     (su_is_server_page(url, "help.js")))
  12423.             return false;
  12424.     }
  12425.     return true;
  12426. }
  12427.  
  12428. function su_handle_page_feature_prompt_click(event)
  12429. {
  12430.     var url = su_get_browser_url();
  12431.     var search_service_id = su_get_service_id(url, true);
  12432.     
  12433.     if (su_is_matching_domain(url, "facebook.com"))
  12434.     {
  12435.         if (su_ds.getValue("$facebook_added"))
  12436.         {
  12437.             su_ds.setValue("$facebook_linked", true);
  12438.             
  12439.             su_set_server_location(
  12440.                         "facebook/index.php?link",
  12441.                         null,
  12442.                         su_new_tab(event));
  12443.         }
  12444.         else
  12445.         {
  12446.             su_set_location(
  12447.                         "http://apps.facebook.com/stumbleupon/",
  12448.                         null,
  12449.                         su_new_tab(event));
  12450.         }
  12451.     }
  12452.     else if (search_service_id)
  12453.     {
  12454.         su_ds.setValue("$show_searchlinks_score", true);
  12455.         su_ds.setValue("$show_searchlinks_friends", true);
  12456.         su_ds.setValue("$shown_searchlinks", true);
  12457.         if (su_new_tab(event))
  12458.         {
  12459.             su_set_location(url, null, true);
  12460.         }
  12461.         else
  12462.         {
  12463.             su_search_results_page(
  12464.                         getBrowser().contentDocument,
  12465.                         search_service_id);
  12466.         }
  12467.     }
  12468.     su_set_visible("su_page_feature_prompt", false);
  12469. }
  12470.  
  12471. // handles the click event for the website_info button
  12472. function su_handle_website_info_click(event)
  12473. {    
  12474.     // button is disabled
  12475.     if (su_get_element("su_website_info").getAttribute("image") == "chrome://stumbleupon/content/skin/bubblex.png")
  12476.         return;
  12477.  
  12478.     su_website_info(su_new_tab(event), "", 0);
  12479. }
  12480.  
  12481. function su_handle_website_info_promo_click(event, from_control_id)
  12482. {    
  12483.     if (su_search_service_id)
  12484.     {
  12485.         su_handle_promo_click(event,     "search");
  12486.         return;
  12487.     }
  12488.     
  12489.     // button is disabled
  12490.     if (su_get_element("su_website_info_promo").disabled)
  12491.         return;
  12492.  
  12493.     var url = su_get_browser_url();        
  12494.     
  12495.     var cmp_url = url.toLowerCase();
  12496.     
  12497.     if (cmp_url.indexOf("http://video." + su_servername + "/#p") == 0)
  12498.         return;
  12499.                 
  12500.     if (cmp_url.indexOf("http://video." + su_servername + "/?p") == 0)
  12501.         return;
  12502.     
  12503.     var loc;
  12504.     var params = null;
  12505.     
  12506.     if (url.indexOf("about:") == 0)
  12507.     {
  12508.         su_verify_cookie_perms(false);
  12509.         loc = "sign_up.php";
  12510.         if (su_ds.getValue("@facebook_user"))
  12511.             loc = su_arp(loc, "pre", "facebook", true);
  12512.         
  12513.         loc = su_arp(loc, "pre2", from_control_id, true); 
  12514.         
  12515.         if (su_host.dist)
  12516.             loc = su_arp(loc, "dist", su_host.dist, true);
  12517.     }
  12518.     else
  12519.     {
  12520.         loc = "url/" + su_review_url(url);
  12521.         params = "";
  12522.         if (su_ds.getValue("@facebook_user"))
  12523.             params = su_arp(params, "pre", "facebook");
  12524.         
  12525.         params = su_arp(params, "pre2", from_control_id); 
  12526.         
  12527.         if (su_host.dist)
  12528.             params = su_arp(params, "dist", su_host.dist);
  12529.         
  12530.         params = su_arp(params, "retry_url", url);
  12531.     }
  12532.     
  12533.     su_set_server_location(
  12534.                 loc,
  12535.                 params,
  12536.                 su_new_tab(event));
  12537. }
  12538.  
  12539. function su_handle_promo_click(event, from_control_id)
  12540. {    
  12541.     var is_search = false;
  12542.     var url = su_get_browser_url();
  12543.     var detail = new Object();
  12544.     if (from_control_id == "search")
  12545.     {
  12546.         is_search = true;
  12547.         from_control_id = su_search_service_id;
  12548.         detail = su_get_search_query_detail(su_search_service_id, url); 
  12549.     }
  12550.     
  12551.     su_verify_cookie_perms(false);
  12552.     var loc = "sign_up.php";
  12553.     var params = null;
  12554.     if (su_ds.getValue("@facebook_user"))
  12555.         loc = su_arp(loc, "pre", "facebook", true);
  12556.     
  12557.     loc = su_arp(loc, "pre2", from_control_id, true); 
  12558.     
  12559.     if (su_host.dist)
  12560.         loc = su_arp(loc, "dist", su_host.dist, true);
  12561.     
  12562.     if (detail.is_short_query_results)
  12563.         params = su_arp("", "post_url", url);
  12564.     else if (detail.is_query_results)
  12565.         params = su_arp("", "post_url2", url);
  12566.     else if (from_control_id == "referral")
  12567.         loc = su_arp(loc, "url", url, true);
  12568.  
  12569.     su_set_server_location(
  12570.                 loc,
  12571.                 params,
  12572.                 su_new_tab(event));
  12573. }
  12574.  
  12575. function su_handle_video_promo_click(event)
  12576. {
  12577.  
  12578.     su_get_element("su_stumble").image="chrome://stumbleupon/content/skin/stumble2.png";
  12579.     su_stumble_action_count++;
  12580.     setTimeout(
  12581.                 su_reset_stumble_action_indicator,
  12582.                 su_ds.getValue("@stumble_action_timeout_ms"),
  12583.                 su_stumble_action_count);
  12584.     
  12585.     su_stumble_video(su_new_tab(event));
  12586. }
  12587.  
  12588. function su_handle_tag_command(force_dialog)
  12589. {
  12590.     var searchbox = su_get_element("su_searchbox");
  12591.     if (searchbox.open)
  12592.         searchbox.closePopup();
  12593.     
  12594.     setTimeout(su_handle_tag_command2, 0, force_dialog);    
  12595. }
  12596.  
  12597. function su_get_title(opt_doc, opt_raw_url)
  12598. {
  12599.     var doc = (opt_doc) ? opt_doc : getBrowser().contentDocument;
  12600.     
  12601.     if (doc.title != "")
  12602.         return doc.title;
  12603.     
  12604.     if (opt_raw_url)
  12605.         return opt_raw_url;
  12606.         
  12607.     return su_get_browser_url(doc, true)
  12608. }
  12609.  
  12610. function su_handle_tag_command2(force_dialog)
  12611. {
  12612.     //!!! canonize tag?
  12613.     var current_url = su_get_browser_url();
  12614.     
  12615.     if (su_url_has_tag)
  12616.     {
  12617.         var tag = su_get_tag_list(current_url);
  12618.         
  12619.         if (tag)
  12620.         {
  12621.             su_tagit(current_url, tag, true, su_get_title(), su_get_browser_url(null, true));
  12622.             return;
  12623.         }
  12624.     }
  12625.     
  12626.     su_unfocus_searchbox(); 
  12627.     // see if searchbox is hidden
  12628.     var tag = '';
  12629.     if (force_dialog || (su_get_element("su_field").collapsed == true))
  12630.     {
  12631.         var detail = new Object();
  12632.         detail.url = current_url;
  12633.         detail.tags_default = su_get_element("su_searchbox").value;
  12634.         if (detail.tags_default == su_tag_instructions)
  12635.             detail.tags_default = "";
  12636.  
  12637.         window.openDialog(
  12638.                     "chrome://stumbleupon/content/taggingDialog.xul",
  12639.                     "",
  12640.                     "chrome,dialog,centerscreen,dependent",
  12641.                     detail);
  12642.     }
  12643.     else
  12644.     {    
  12645.         tag = su_get_element("su_searchbox").value;
  12646.         if (tag == su_tag_instructions)
  12647.             tag = "";
  12648.         
  12649.         if (tag == "")
  12650.         {
  12651.             // put a little instruction thing up
  12652.             var alerttext = "To tag a page, type some tags into the text box before clicking the tag button.\nTags are descriptive keywords you can use to organize and share useful websites.\nTags may contain spaces, letters, and numbers and must be separated by commas.\nFor example, you might tag page of travel photos as \"photos, traveling, costa rica\".\n\nYou can lookup sites you've tagged using the 'Find pages you liked' button on your Favorites page.";
  12653.             alert(alerttext);
  12654.             
  12655.             // put focus in search box
  12656.             su_get_element("su_searchbox").focus();
  12657.             return;    
  12658.         }    
  12659.         
  12660.         var tagerror = su_validate_tagstring(tag);
  12661.         if (tagerror != null)
  12662.         {
  12663.             alert(tagerror);
  12664.             return;
  12665.         }    
  12666.         su_tagit(current_url, tag, false, su_get_title(), su_get_browser_url(null, true));
  12667.     }    
  12668. }
  12669.  
  12670. function su_validate_tagstring(str)
  12671. {
  12672.     // validate tag...
  12673.     var tags = str.split(',');
  12674.     var tagerror = null;
  12675.     // Itetag through commands
  12676.     var tagcount = 0;
  12677.     for (var i = 0; i < tags.length; i++)
  12678.     {
  12679.         if (tags[i] == "")
  12680.             continue;
  12681.         tagcount++;
  12682.         if (tagcount > 5)
  12683.         {
  12684.             tagerror = 'You cannot apply more than 5 tags to a page.';
  12685.             break;
  12686.         }
  12687.         
  12688.         var thetag = tags[i];
  12689.         
  12690.         if (thetag.indexOf('http://') != -1)
  12691.         {
  12692.             tagerror = 'If you want to search for a site, enter some search terms then click \'enter\'.\nTo tag a page, type in some keywords before clicking this icon.';
  12693.             break;    
  12694.         }
  12695.         
  12696.         if (thetag.length > 32)
  12697.         {
  12698.             tagerror = 'Each tag cannot be longer than 32 characters.\nYour tag \'' + thetag + '\' is ' + thetag.length + ' characters long.';
  12699.             break;
  12700.         }
  12701.         var tagpieces = thetag.split(/[^A-Za-z0-9]/);
  12702. //        alert(tagpieces.length);
  12703.         var tagpiececount = 0;
  12704.         for (var j = 0; j < tagpieces.length; j++)
  12705.         {
  12706.             if (tagpieces[j] == "")
  12707.                 continue;
  12708.             //alert(tagpieces[j]);
  12709.             tagpiececount++;
  12710.             if (tagpiececount > 3)
  12711.             {
  12712.                 tagerror = 'Each tag cannot have more than 3 words. For example,\n \'costa rica trip\' is a valid tag, but \'costa rica trip photos\' is not.\nYour tag \'' + thetag + '\' has ' + tagpiececount + ' words.';
  12713.                 break;    
  12714.             }
  12715.         }
  12716.         if (tagpiececount > 3)
  12717.             break;    
  12718.     }
  12719.     return tagerror;
  12720. }
  12721.  
  12722. function su_tagit(url, tag, untag, opt_title, opt_raw_url)
  12723. {
  12724.     // when you tag, we know it's not a tag on i-likeit
  12725.     su_last_typed_tag = 0;
  12726.     
  12727.     if ((url == "") || (url.indexOf("about:") == 0))
  12728.         return;
  12729.  
  12730.     var context = new su_AsyncContext();
  12731.     context.url = url;
  12732.     context.tag = tag;
  12733.     context.ref_url = (opt_raw_url) ? opt_raw_url : su_get_browser_url(null, true);
  12734.     context.untagging = untag;
  12735.     if (! untag)
  12736.         context.title = (opt_title) ? opt_title : su_get_title();
  12737.     
  12738.     var params = "tag=" + escape(tag) + "&url=" + encodeURIComponent(url);
  12739.     
  12740.     params = su_arp(params, "referer", su_get_browser_referrer_url());
  12741.     
  12742.     params = su_append_sync_params(params);
  12743.     
  12744.     if (untag)
  12745.     {
  12746.         // we want to undo this tag    
  12747.         su_post_url_server_async(
  12748.                     "untagit.php",
  12749.                     params,
  12750.                     null,
  12751.                     su_untag_done,
  12752.                     context);
  12753.     }
  12754.     else
  12755.     {
  12756.         su_post_url_server_async(
  12757.                     "tagit.php",
  12758.                     params,
  12759.                     null,
  12760.                     su_tag_done,
  12761.                     context);
  12762.     }
  12763.     return;
  12764. }
  12765.  
  12766.  
  12767. function su_untag_done(res)
  12768. {
  12769.     try {
  12770.         if (res.status == 1)
  12771.             return;
  12772.     } catch (e) { return; }
  12773.     
  12774.     if (res.status != 200)
  12775.     {
  12776.         su_http_error(res.error, res.status);
  12777.         return;
  12778.     }
  12779.     
  12780.     var context = res.detail;
  12781.     
  12782.     // success!
  12783.     // !!! go to info page? (middle click or option?)
  12784.     
  12785.     var s = "";
  12786.     if (typeof(res.responseText) != "undefined")
  12787.         s = res.responseText;
  12788.  
  12789.     if (su_log_communication)
  12790.         su_log("response untagit.php", s);
  12791.     
  12792.     su_process_commands(s, context);
  12793.     if (context.error)
  12794.         return;
  12795.     
  12796.     su_load_tags(context.url);
  12797.     su_store_tags();
  12798.     
  12799.     su_enable_tag_toolbar();
  12800.     
  12801.     return;
  12802. }
  12803.  
  12804.  
  12805. function su_tag_done(res)
  12806. {
  12807.     try {
  12808.         if (res.status == 1)
  12809.             return;
  12810.     } catch (e) { return; }
  12811.     
  12812.     if (res.status != 200)
  12813.     {
  12814.         su_http_error(res.error, res.status);
  12815.         return;
  12816.     }
  12817.     
  12818.     var context = res.detail;
  12819.     
  12820.     // success!
  12821.     // !!! go to info page? (middle click or option?)
  12822.  
  12823.     var s = "";
  12824.     if (typeof(res.responseText) != "undefined")
  12825.         s = res.responseText;
  12826.     
  12827.     if (su_log_communication)
  12828.         su_log("response tagit.php", s);
  12829.     
  12830.     su_process_commands(s, context);
  12831.     if (context.error)
  12832.         return;
  12833.     
  12834.     var tag = su_normalize_tag(context.tag);
  12835.     
  12836.     su_load_tags(context.url);
  12837.     
  12838.     // Add the new tag
  12839.     var o = new Object();
  12840.     o.url = context.url;
  12841.     o.tag_list = tag;
  12842.     su_tag_lists_by_url[context.url] = tag;
  12843.     su_tags.unshift(o);
  12844.     
  12845.     su_store_tags();
  12846.     
  12847.     su_disable_tag_toolbar(tag);
  12848.     su_old_search = tag;
  12849.     
  12850.     su_get_element("su_tag").image="chrome://stumbleupon/content/skin/tag2.png";
  12851.     su_get_element("su_tag2").image="chrome://stumbleupon/content/skin/tag2.png";
  12852. }
  12853.  
  12854.  
  12855. // Returns the size of the URL in bytes; must be cached and therefore an HTTP or FTP URL
  12856. function su_get_size(url) 
  12857. {
  12858.     var cacheService = su_get_service(
  12859.                 "@mozilla.org/network/cache-service;1",
  12860.                 "nsICacheService");
  12861.     var httpCacheSession = cacheService.createSession("HTTP", 0, true);
  12862.     httpCacheSession.doomEntriesIfExpired = false;
  12863.     var ftpCacheSession = cacheService.createSession("FTP", 0, true);
  12864.     ftpCacheSession.doomEntriesIfExpired = false;
  12865.     
  12866.     try
  12867.     {
  12868.         var cacheEntryDescriptor = httpCacheSession.openCacheEntry(url, Components.interfaces.nsICache.ACCESS_READ, false);
  12869.         if (cacheEntryDescriptor)
  12870.             return cacheEntryDescriptor.dataSize;
  12871.     }
  12872.     catch(ex) {}
  12873.     try
  12874.     {
  12875.         cacheEntryDescriptor = ftpCacheSession.openCacheEntry(url, Components.interfaces.nsICache.ACCESS_READ, false);
  12876.         if (cacheEntryDescriptor)
  12877.             return cacheEntryDescriptor.dataSize;
  12878.     }
  12879.     catch(ex) {}
  12880.     return -1;
  12881. }
  12882.  
  12883. // Handler for photoblog
  12884. function su_blogImage(rating)
  12885. {
  12886.     su_photoblogimage = document.popupNode;
  12887.  
  12888.     if (su_get_size(su_photoblogimage.src) > 250000)
  12889.     {
  12890.         su_photoblogimage = null;
  12891.         alert("Image too large (250kb max size)");
  12892.         return;
  12893.     }
  12894.  
  12895.     if (su_photoblogimage.width > 715)
  12896.     {
  12897.         su_photoblogimage = null;
  12898.         alert("Image too large (715px max width)");
  12899.         return;
  12900.     }
  12901.  
  12902.     if (su_photoblogimage.height > 715)
  12903.     {
  12904.         su_photoblogimage = null;
  12905.         alert("Image too large (715px max height)");
  12906.         return;
  12907.     }
  12908.  
  12909. /*
  12910.     // see if we need to grab the referring page for this image
  12911.     var current_page = su_get_browser_url();
  12912.     alert("currente page: " + current_page + " su_photoblogimage: " + su_photoblogimage.src);
  12913.     if (current_page == su_photoblogimage.src)
  12914.     {
  12915.         // we want to find the referring page...
  12916.         var referer = getBrowser().contentDocument.referrer;
  12917.         alert("referer " + referer);
  12918.         if (typeof(referer) != "undefined" && referer != null && referer != "" && referer.indexOf('http://') != -1)
  12919.         {
  12920.             // we need to rate the referering page..     
  12921.             alert("refering page: " + referer);
  12922.             return;
  12923.         }
  12924.     }
  12925.  
  12926.     alert("no referring page");
  12927.     return;
  12928. */
  12929.  
  12930.     // first do rating...
  12931.     su_rate(rating, false, true, false, 0);    
  12932. }
  12933.  
  12934. // pre-Handler for button "rate"
  12935. function su_handle_rate_click(event, r)
  12936. {
  12937.     if (su_promo_mode && (stumbleid == 0) && (! su_get_stumblevideo_detail()))
  12938.     {
  12939.         if (r > 0)
  12940.             su_handle_website_info_promo_click(event, "thumbup");
  12941.         else
  12942.             su_handle_website_info_promo_click(event, "thumbdown");
  12943.             
  12944.         return;
  12945.     }
  12946.     
  12947.     if (r == 2)
  12948.     {
  12949.         r = 1;
  12950.         su_d_rec_rating = true;
  12951.     }
  12952.     else
  12953.     {
  12954.         su_d_rec_rating = false;
  12955.     }
  12956.     
  12957.     var url = su_get_browser_url();
  12958.     var old_rating = su_get_rating(url, (su_get_stumblevideo_detail() != null));
  12959.     
  12960.     // see if they are unrating an old rating
  12961.     
  12962.     if ((old_rating != null) && 
  12963.             ((old_rating == r) || (r == 0 && (old_rating <= 0))))
  12964.     {
  12965.         setTimeout(su_unrate, 0);
  12966.         return;
  12967.     }
  12968.     
  12969.     if (su_get_element("su_thumbup").disabled == true)
  12970.         return;
  12971.     
  12972.     if (typeof(event.button) == "undefined")
  12973.         event.button = 0; // For menu entries, simulate left button
  12974.  
  12975.     var platform_ctrl_key = (su_host.mac) ? event.metaKey : event.ctrlKey;
  12976.     
  12977.     if (((event.button == 0) && (! platform_ctrl_key)) && 
  12978.                 (! su_ds.getValue("$rate_new_window")))
  12979.         su_rate(r, false, false, false, 0);
  12980.     
  12981.     else if ((event.button == 1) || ((event.button == 0) && 
  12982.                 platform_ctrl_key) || su_ds.getValue("$rate_new_window"))
  12983.         su_rate(r, true, false, false, 0);
  12984. }
  12985.  
  12986.  
  12987. // Handler for button "rate"
  12988. function su_unrate()
  12989. {
  12990.     su_check_progress_listener();
  12991.  
  12992.     if ((stumbleid == 0) && (! su_promo_mode))
  12993.         return;
  12994.     
  12995.     var theurl = su_get_browser_url();
  12996.     if (stumbled_redirect != '' && theurl == stumbled_redirect)
  12997.     {
  12998.         // we have a redirect, rate the original url we stumbled on
  12999.         theurl = stumbled_url;
  13000.     }
  13001.  
  13002.     var sv_detail = su_get_stumblevideo_detail();
  13003.                 
  13004.     if (sv_detail)
  13005.     {
  13006.         var doc = getBrowser().contentDocument;
  13007.         
  13008.         su_stumblevideo_toolbar_rate = true;
  13009.         var thumbup = doc.getElementById("thumbUp");
  13010.         var thumbdown = doc.getElementById("thumbDown");
  13011.         if (thumbup.src.indexOf("_sel") != -1)
  13012.             su_dispatch_click(doc, "thumbUp");
  13013.         else if (thumbdown.src.indexOf("_sel") != -1)
  13014.             su_dispatch_click(doc, "thumbDown");
  13015.         return;
  13016.     }
  13017.     
  13018.     // grey out the buttons until the rating goes through
  13019.     su_get_element("su_thumbup").disabled=true;
  13020.     su_get_element("su_thumbdown").disabled=true;
  13021.     su_get_element("su_thumbup").setAttribute("onclick", "");
  13022.  
  13023.     var params = "";
  13024.     params = su_arp(params, "url", theurl); 
  13025.     params = su_append_sync_params(params);
  13026.     
  13027.     var context = new su_AsyncContext();
  13028.     context.url = theurl;
  13029.     context.ref_url = context.url;
  13030.     su_post_url_server_async(
  13031.                 "unrate.php",
  13032.                 params,
  13033.                 null,
  13034.                 su_unrate_done,
  13035.                 context);
  13036.  
  13037.     su_check_progress_listener();
  13038. }
  13039.  
  13040. function su_unrate_done(res)
  13041. {
  13042.     try {
  13043.         if (res.status == 1)
  13044.         {
  13045.             su_enable_toolbar();
  13046.             return;
  13047.         }
  13048.     } catch (e) { return; }
  13049.     
  13050.     if (res.status != 200)
  13051.     {
  13052.         su_http_error(res.error, res.status);
  13053.         su_enable_toolbar();
  13054.         return;
  13055.     }
  13056.     
  13057.     var context = res.detail;
  13058.     context.unrating = true;
  13059.  
  13060.     var s = "";
  13061.     if (typeof(res.responseText) != "undefined")
  13062.         s = res.responseText;
  13063.  
  13064.     if (su_log_communication)
  13065.         su_log("response unrate.php", s);
  13066.  
  13067.     su_process_commands(s, context);
  13068.     if (context.error && !context.discoveryCancelled)
  13069.     {
  13070.         su_enable_toolbar();
  13071.         return;
  13072.     }
  13073.     
  13074.     // Store in list of rated urls
  13075.     su_delete_rating(context.url);
  13076.  
  13077.     su_refresh_pagemeta(false, 3);
  13078.     
  13079.     su_check_progress_listener();
  13080. }
  13081.  
  13082. // Handler for button "rate"
  13083. function su_block_domain()
  13084. {
  13085.     var url = su_get_browser_url();
  13086.     
  13087.     var rating = su_get_rating(url, (su_get_stumblevideo_detail() != null));
  13088.     
  13089.     var domain = su_get_tld(url);
  13090.     
  13091.     var blk_domain = su_is_domain_blocked(domain) ? -1 : 1;
  13092.     
  13093.     if (rating == null && blk_domain == 1)
  13094.         rating = -2;
  13095.     
  13096.     if (rating == null && blk_domain == -1)
  13097.     {
  13098.         var context = new su_AsyncContext();
  13099.         context.url = url;
  13100.         context.ref_url = url;
  13101.         var params = "";
  13102.         params = su_arp(params, "url", url); 
  13103.         params = su_arp(params, "blkdomain", -1); 
  13104.         params = su_append_sync_params(params);
  13105.         su_post_url_server_async(
  13106.                     "unrate.php",
  13107.                     params,
  13108.                     null,
  13109.                     su_unrate_done,
  13110.                     context);
  13111.     }
  13112.     else
  13113.     {
  13114.         su_rate(rating, false, true, false, blk_domain, url);
  13115.     }
  13116. }
  13117.  
  13118. // Handler for button "rate"
  13119. function su_rate(r, open_reviews, force_nostumble, force_comment, blk_domain, opt_url) 
  13120. {
  13121.     su_register_activity("rate");
  13122.     su_check_progress_listener();
  13123.     try {
  13124.         su_close_info();
  13125.     } catch (e) {}
  13126.     
  13127.     // If we are opening a comment button in a new tab
  13128.     // we shouldn't be stumbling
  13129.     if (open_reviews)
  13130.         force_nostumble = true;
  13131.  
  13132.     if ((stumbleid == 0) && (! su_promo_mode))
  13133.         return;
  13134.     
  13135.     var rating = r;
  13136.  
  13137.     var theurl = (opt_url) ? opt_url : su_get_browser_url();
  13138.  
  13139. //    su_dd("rate", theurl, stumbled_redirect);
  13140.     
  13141. //    return;
  13142.     
  13143.     
  13144.     if (stumbled_redirect != '' && theurl == stumbled_redirect)
  13145.     {
  13146.         // we have a redirect, rate the original url we stumbled on
  13147.         theurl = stumbled_url;
  13148.     }
  13149.  
  13150.     if (rating > 0)
  13151.     {
  13152.         // We try to keep our own local thumbup count but defer to the server when it sends an
  13153.         // SFC command
  13154.         su_ds.incrementValue("$thumbup_count");
  13155.         su_thumbup_count_changed();
  13156.     }
  13157.     else
  13158.         su_ds.incrementValue("$thumbdown_count");
  13159.     
  13160.     var sv_detail = su_get_stumblevideo_detail();
  13161.                 
  13162.     if (sv_detail &&
  13163.                 (! ((su_ds.getValue("$bad_stumble", false) && rating <= 0)
  13164.                 || (su_ds.getValue("$great_stumble", false) && rating == 1))))
  13165.     {
  13166.         var doc = getBrowser().contentDocument;
  13167.  
  13168.         su_stumblevideo_toolbar_rate = true;
  13169.         if (rating == 1)
  13170.             su_dispatch_click(doc, "thumbUp");
  13171.         else if (rating <= 0)
  13172.             su_dispatch_click(doc, "thumbDown");
  13173.  
  13174.         return;
  13175.     }
  13176.     else if (sv_detail)
  13177.     {
  13178.         theurl = sv_detail.url;
  13179.     }
  13180.     
  13181.     var cmp_url = theurl.toLowerCase();
  13182.     if (cmp_url.indexOf("http://video." + su_servername + "/#p") == 0)
  13183.         return;
  13184.                 
  13185.     if (cmp_url.indexOf("http://video." + su_servername + "/?p") == 0)
  13186.         return;
  13187.  
  13188.     // grey out the buttons until the rating goes through
  13189.     su_get_element("su_thumbup").disabled=true;
  13190.     su_get_element("su_thumbdown").disabled=true;
  13191.     su_get_element("su_thumbup").setAttribute("onclick", "");
  13192.  
  13193.     su_quote = "";
  13194.     if (getBrowser().contentWindow.getSelection)
  13195.         su_quote = getBrowser().contentWindow.getSelection().toString();
  13196.  
  13197.     var charset = "";
  13198.     var webShell = getBrowser().docShell.QueryInterface(Components.interfaces.nsIDocCharset);
  13199.     if (webShell)
  13200.         charset = webShell.charset;
  13201.     
  13202.     var doc = getBrowser().contentDocument;
  13203.     var context = new su_AsyncContext();
  13204.     context.rating = rating;
  13205.     context.url = theurl;
  13206.     context.ref_url = su_get_browser_url(doc, true);
  13207.     context.browser = getBrowser().selectedBrowser;
  13208.     context.title = su_get_title(doc, context.ref_url);
  13209.     context.force_nostumble = force_nostumble;
  13210.     context.force_comment = force_comment;
  13211.     context.timestamp = (new Date()).getTime();
  13212.     context.open_reviews = open_reviews;
  13213.     context.charset = charset;
  13214.     context.referrer = doc.referrer;
  13215.     context.stumblevideo_mode = null;
  13216.     context.blk_domain = blk_domain;
  13217.     
  13218.     var postdata = "rating=" + rating + 
  13219.                     '&url=' + encodeURIComponent(theurl) + 
  13220.                     "&charset=" + encodeURIComponent(charset) + 
  13221.                     "&referer=" + encodeURIComponent(context.referrer) +
  13222.                     "&blkdomain=" + blk_domain;
  13223.     
  13224.     if (sv_detail)
  13225.         postdata += "&videoperma=1";
  13226.     
  13227.     postdata = su_append_sync_params(postdata);
  13228.     
  13229.     su_post_url_server_async(
  13230.                 "rate.php",
  13231.                 postdata,
  13232.                 null,
  13233.                 su_rate_done,
  13234.                 context);
  13235.     
  13236.     su_check_progress_listener();
  13237. }
  13238.  
  13239. function su_rate_done(res)
  13240. {
  13241.     try {
  13242.         if (res.status == 1)
  13243.         {
  13244.             su_enable_toolbar();
  13245.             return;
  13246.         }
  13247.     } catch (e) { return; }
  13248.     
  13249.     if (res.status != 200)
  13250.     {
  13251.         su_http_error(res.error, res.status);
  13252.         su_enable_toolbar();
  13253.         return;
  13254.     }
  13255.     
  13256.     var context = res.detail;
  13257.     
  13258.     if (context.browser == getBrowser().selectedBrowser)
  13259.     {
  13260.         if ((context.stumblevideo_mode == "page") || 
  13261.                     (! su_ds.getValue("$bad_stumble") && 
  13262.                         (context.rating <= 0)) || 
  13263.                     (! su_ds.getValue("$great_stumble") && 
  13264.                         (context.rating == 1))) 
  13265.             su_disable_toolbar(context.rating);
  13266.     }
  13267.     
  13268.     
  13269.     var s = "";
  13270.     if (typeof(res.responseText) != "undefined")
  13271.         s = res.responseText;
  13272.     
  13273.     if (su_log_communication)
  13274.         su_log("response rate.php", s);
  13275.     
  13276.     // Parse response text
  13277.     var parsed = s.split("\n");
  13278.     var prepend = "";
  13279.     var discovery = false;
  13280.     var firstrate = 0;
  13281.     var canceled = false;
  13282.     
  13283.     // Iterate through commands
  13284.     for (var i = 0; i < parsed.length; i++)
  13285.     {
  13286.         if (parsed[i] == "")
  13287.             continue;
  13288.  
  13289.         // Parse command structure
  13290.         var command = parsed[i].split(" ");
  13291.         switch(command[0])
  13292.         {
  13293.             case "URL": prepend += command[1] + "\n"; break;
  13294.             case "FIRSTRATER": firstrate = command[1]; break;
  13295.             case "NEWURL" : 
  13296.                 // do 800x600+
  13297.                 if (context.rating == 1)
  13298.                 {
  13299.                     discovery = true;
  13300.                     su_disable_toolbar(context.rating);
  13301.                     var detail = new Object();
  13302.                     detail.finalized = false;
  13303.                     detail.submitted = false;
  13304.                     detail.url = context.url;
  13305.                     detail.uri_suffix = "newurl.php";
  13306.                     detail.tagtext = "";
  13307.                     detail.postdata = "url=" + encodeURIComponent(context.url) + 
  13308.                                 "&title=" + encodeURIComponent(context.title) + 
  13309.                                 "&charset=" + encodeURIComponent(context.charset) + 
  13310.                                 "&rating=" + context.rating + 
  13311.                                 ""e=" + encodeURIComponent(su_quote) + 
  13312.                                 "&referer=" + encodeURIComponent(context.referrer) +
  13313.                                 "&catidlist=" + encodeURIComponent('');
  13314.     
  13315.                     if (su_photoblogimage)
  13316.                     {
  13317.                         detail.postdata += "&image=" + encodeURIComponent(su_photoblogimage.src) + 
  13318.                                     "&width=" + su_photoblogimage.width + 
  13319.                                     "&height=" + su_photoblogimage.height;
  13320.                         su_photoblogimage = null;
  13321.                     }
  13322.         
  13323.                     var width = (command.length >= 2) ? parseInt(command[1]) : 700;
  13324.                     var height = (command.length >= 3) ? parseInt(command[2]) : 450;
  13325.                     
  13326.                     var dialog_url = "chrome://stumbleupon/content/discoveryDialog.xul";
  13327.                     dialog_url += "#d" + su_ds.incrementValue("~discovery_count");
  13328.                     
  13329.                     su_ds.define("disc_dialog_url:disc_detail", dialog_url, detail);
  13330.                     su_ds.addEventListener(
  13331.                             "discdlgclose",
  13332.                             function (event) {
  13333.                                 window.su_handle_discovery_dialog_close(event); });
  13334.                     
  13335.                     window.openDialog(
  13336.                                 dialog_url,
  13337.                                 "",
  13338.                                 "chrome,dialog,centerscreen,width=" + width + 
  13339.                                     ",height=" + height + 
  13340.                                     ",resizable=1",
  13341.                                 detail);
  13342.                     
  13343.                     // calculate this before we get the add comment
  13344.                     var da = new Date();
  13345.                     var now = da.getTime();
  13346.                     // Store in list of rated urls
  13347.                     
  13348.                     su_store_rating(context.url, (su_d_rec_rating) ? 2 : context.rating);
  13349.                 }
  13350.                 else if ((context.rating <= 0) && 
  13351.                             (context.browser == getBrowser().selectedBrowser))
  13352.                 {
  13353.                     var tmpres = new Object();
  13354.                     tmpres.detail = new su_AsyncContext();
  13355.                     tmpres.detail.url = context.url;
  13356.                     tmpres.status = 200;
  13357.                     tmpres.responseText = "";
  13358.                     su_unrate_done(tmpres);
  13359.                     canceled = true;
  13360.                     if (context.blk_domain == 0)
  13361.                         setTimeout(su_show_thumbdown_discovery_alert, 0);
  13362.                 }
  13363.                 
  13364.                 var time_between_tagging = now - su_last_typed_tag;
  13365.                 var i_just_stumbled = false;
  13366.                                 
  13367.                 return;
  13368.             default:
  13369.                 su_process_command(parsed[i], context, command);
  13370.                 if (context.error)
  13371.                 {
  13372.                     su_enable_toolbar();
  13373.                     return;
  13374.                 }
  13375.                 break;
  13376.         }
  13377.     }
  13378.     
  13379.     setTimeout(su_refresh_pagemeta, 0, false, 9);
  13380.     
  13381.     if (canceled)
  13382.         return;
  13383.     
  13384.     if ((context.rating == 1) && (! discovery))
  13385.     {
  13386.         if (! su_ds.getValue("$shown_reviews_info"))
  13387.             su_display_info("reviews");
  13388.         else if (! su_ds.getValue("$shown_referral_info"))
  13389.             su_display_info("referral");
  13390.     }
  13391.     
  13392.     // Store in list of rated urls
  13393.     su_store_rating(context.url, (su_d_rec_rating) ? 2 : context.rating);
  13394.  
  13395.     // Prepend URLs if we got any
  13396.     if (prepend != "")
  13397.     {
  13398.         prior = su_read_file_user("stumbleurls");
  13399.         su_write_file_user("stumbleurls", prepend + prior);
  13400.     }
  13401.  
  13402.     var searchbox_value = su_get_element("su_searchbox").value;
  13403.     if ((! su_ds.getValue("$show_field")) || (searchbox_value == su_tag_instructions))
  13404.         searchbox_value = "";
  13405.         
  13406.     // calculate this before we get the add comment
  13407.     var now = (new Date()).getTime();
  13408.     var time_between_tagging = now - su_last_typed_tag;
  13409.     var opened_website_info = false;
  13410.     if (su_photoblogimage)
  13411.     {
  13412.         opened_website_info = true;
  13413.         su_website_info(false, context.url, firstrate);
  13414.     }
  13415. //    else if (context.force_comment || ((! context.open_reviews) && 
  13416. //                su_ds.getValue("$comment_firstrating") && firstrate != 0))
  13417. //    {
  13418. //        su_unfocus_searchbox();
  13419. //
  13420. //        window.openDialog(
  13421. //                    "chrome://stumbleupon/content/ratingDialog.xul",
  13422. //                    "StumbleUpon Review",
  13423. //                    "chrome,modal,dialog,centerscreen,dependent", 
  13424. //                    context.url, 
  13425. //                    firstrate, 
  13426. //                    searchbox_value,
  13427. //                    su_quote);
  13428. //    }
  13429.     
  13430.     var tag_term = su_get_element('su_searchbox').value;
  13431.     
  13432.     // if they've typed a tag in within the last 10 seconds, tag it
  13433.     if (context.rating == 1 && tag_term != '' && su_last_typed_tag != 0 && time_between_tagging < 1000 * 6)
  13434.     {
  13435.         su_tagit(context.url, tag_term, false, context.title, context.ref_url);
  13436.         
  13437.         // clear it once we are done..
  13438.         su_last_typed_tag = 0;
  13439.         su_old_search = '';
  13440.         //su_get_element('su_searchbox').value = '';
  13441.     }
  13442.         
  13443.     var i_just_stumbled = false;
  13444.     
  13445.     // Stumble-On-Rate
  13446.     if ( (! context.force_nostumble) && 
  13447.         ((su_ds.getValue("$bad_stumble") && context.rating <= 0)
  13448.         || (su_ds.getValue("$great_stumble") && context.rating == 1)) ) 
  13449.     {
  13450.         stumble(0);    
  13451.         i_just_stumbled = true;
  13452.     }
  13453.     
  13454.     if ((! opened_website_info) && (! i_just_stumbled) && 
  13455.                 context.open_reviews && (context.rating == 1) && 
  13456.                 (context.stumblevideo_mode != "page"))
  13457.     {
  13458.         su_website_info(0, context.url, 0);
  13459.     }
  13460.     
  13461.     su_check_progress_listener();
  13462. }
  13463.  
  13464. function su_prepare_thumbdown_menu()
  13465. {
  13466.     var url = su_get_browser_url();
  13467.     
  13468.     var rating = su_get_rating(url, (su_get_stumblevideo_detail() != null));
  13469.         
  13470.     // Handle checks
  13471.     su_get_element('su_thumbdown_menu_notforme').setAttribute("checked", ((rating == -2) || (rating == 0))); 
  13472.     su_get_element('su_thumbdown_menu_spam').setAttribute("checked", (rating == -5));
  13473.     su_get_element('su_thumbdown_menu_dupe').setAttribute("checked", (rating == -3));
  13474. //    su_get_element('su_thumbdown_menu_saturation').setAttribute("checked", (rating == -4));
  13475.  
  13476.     if (! su_host.places)
  13477.     {
  13478.         su_get_element('su_thumbdown_menu_blockdomain').hidden = true;
  13479.         su_get_element("su_thumbdown_menu_separator").hidden = true;
  13480.         return;
  13481.     }
  13482.     su_get_element("su_thumbdown_menu_separator").hidden = false;
  13483.     
  13484.     var el = su_get_element('su_thumbdown_menu_blockdomain');
  13485.     el.hidden = false; // for good measure
  13486.  
  13487.     // Handle block domain label
  13488.     
  13489.     var domain = su_get_tld(url);
  13490.  
  13491.     if (domain == null)
  13492.     {
  13493.         el.disabled = true;
  13494.         el.label = "Website: ''";
  13495.         el.setAttribute("checked", "false");
  13496.     }
  13497.     else if (domain == su_servername)
  13498.     {
  13499.         el.disabled = true;
  13500.         el.label = "Website: '" + domain + "'";
  13501.         el.setAttribute("checked", "false");
  13502.     }
  13503.     else if (su_is_domain_blocked(domain))
  13504.     {
  13505.         el.disabled = false
  13506.         el.label = "Unblock website: '" + domain + "'";
  13507.         el.setAttribute("checked", "true");
  13508.     }
  13509.     else
  13510.     {
  13511.         el.disabled = false
  13512.         el.label = "Block website: '" + domain + "'";
  13513.         el.setAttribute("checked", "false");
  13514.     }
  13515. }
  13516.  
  13517. function su_show_thumbdown_discovery_alert()
  13518. {
  13519.  
  13520.     var promptService = su_get_service(
  13521.                 "@mozilla.org/embedcomp/prompt-service;1",
  13522.                 "nsIPromptService");
  13523.     
  13524.     promptService.alert(
  13525.             window,
  13526.             "Rating Canceled",
  13527.             "This page is new to StumbleUpon.  Use the \n" +
  13528.                 "'I like it!' button to add it.");
  13529. }
  13530.  
  13531. function su_handle_discovery_dialog_close(event)
  13532. {
  13533.     var detail = su_ds.lookup("disc_dialog_url:disc_detail", event.URL);
  13534.     
  13535.     if (detail.finalized)
  13536.         return;
  13537.     
  13538.     detail.finalized = true;
  13539.     
  13540.     if (detail.submitted)
  13541.     {
  13542.         su_rate_getmeta(detail.url, true);
  13543.         
  13544.         if (detail.tagtext != "")
  13545.         {
  13546.             var count = su_ds.getValue("$tagged_discovery_count");
  13547.             count ++;
  13548.             su_ds.setValue("$tagged_discovery_count", count);
  13549.             if (count == 3)
  13550.             {
  13551.                 su_ds.setValue("$show_tag", true);
  13552.                 su_ds.setValue("$shown_tag", true);
  13553.                 su_ds.setValue("$show_flag", true);
  13554.                 su_set_visible("su_tag",  su_ds.getValue("$show_field"));
  13555.                 su_set_visible("su_tag2", (! su_ds.getValue("$show_field")));
  13556.     //            setTimeout(
  13557.     //                        alert,
  13558.     //                        500,
  13559.     //                        "For convenience, the Tag control has been added to the toolbar.\nIf this is unwelcome, you can remove it via:\ntoolbar->Tools->Toolbar Options.");
  13560.             }
  13561.             
  13562.             var tag = su_normalize_tag(detail.tagtext);
  13563.         
  13564.             su_load_tags(detail.url);
  13565.             
  13566.             // Add the new tag
  13567.             var o = new Object();
  13568.             o.url = detail.url;
  13569.             o.tag_list = tag;
  13570.             su_tag_lists_by_url[detail.url] = tag;
  13571.             su_tags.unshift(o);
  13572.             
  13573.             su_store_tags();
  13574.         
  13575.             su_disable_tag_toolbar(tag);
  13576.             su_old_search = tag;
  13577.         }
  13578.     }
  13579.     else
  13580.     {
  13581.         var context = new su_AsyncContext();
  13582.         context.url = detail.url;
  13583.         context.ref_url = context.url;
  13584.         context.quiet = true;
  13585.         context.discoveryCancelled = true;
  13586.         var params = "url=" + encodeURIComponent(context.url); 
  13587.     
  13588.         params = su_append_sync_params(params);
  13589.     
  13590.         su_post_url_server_async(
  13591.                     "unrate.php",
  13592.                     params,
  13593.                     null,
  13594.                     su_unrate_done,
  13595.                     context);
  13596.     }
  13597.     su_check_progress_listener();
  13598. }
  13599.  
  13600. function su_prepare_reporting_menu(submenu, url_detail, tools_menu, url)
  13601. {
  13602.     var stumbler_name = su_get_profile_nickname(url);
  13603.     
  13604.     var item;
  13605.     if (! tools_menu)
  13606.     {
  13607.         item = document.createElement("menuitem");
  13608.         item.setAttribute("label", "This stumble is:");
  13609.         item.setAttribute("style", "font-weight: bold; color: #404040;");
  13610.         item.setAttribute("disabled", "true");
  13611.         submenu.appendChild(item);
  13612.     }
  13613.     
  13614.     if (! stumbler_name)
  13615.     {
  13616.         item = document.createElement("menuitem");
  13617.         item.setAttribute("label", " Broken or 404");
  13618.         item.setAttribute("tooltiptext", "Report that this page is broken");
  13619.         item.setAttribute("oncommand", "su_handle_report_404_command('" + url + "');");
  13620.         submenu.appendChild(item);
  13621.     }
  13622.  
  13623.     item = document.createElement("menuitem");
  13624.     item.setAttribute("label", " Factually incorrect");
  13625.     item.setAttribute("tooltiptext", "Report that this page contains bogus info");
  13626.     item.setAttribute("oncommand", "su_handle_report_inaccurate_command('" + url + "');");
  13627.     submenu.appendChild(item);
  13628.     
  13629.     if (tools_menu)
  13630.     {
  13631.         if (stumbler_name)
  13632.         {
  13633.             item = document.createElement("menuitem");
  13634.             item.setAttribute("label", " Adult content...");
  13635.             item.setAttribute("tooltiptext", "Report that the " + stumbler_name + " profile contains adult content");
  13636.             item.setAttribute("oncommand", "su_handle_report_adult_profile_command('" + url + "');");
  13637.             submenu.appendChild(item);
  13638.         }
  13639.         else
  13640.         {
  13641.             item = document.createElement("menuitem");
  13642.             if (url_detail)
  13643.                 item.setAttribute("label", " Not about " + url_detail.cur_topic_name + "...");
  13644.             else
  13645.                 item.setAttribute("label", " Suggest topic change...");
  13646.             item.setAttribute("tooltiptext", "Choose a different topic for this page");
  13647.             item.setAttribute("oncommand", "su_handle_report_miscat_command('" + url + "');");
  13648.             submenu.appendChild(item);
  13649.         }
  13650.     }
  13651.     
  13652.     if (url_detail && url_detail.language)
  13653.     {
  13654.         item = document.createElement("menuitem");
  13655.         item.setAttribute("label", " Not in " + url_detail.language + "...");
  13656.         item.setAttribute("tooltiptext", "Choose a different language for this page");
  13657.         item.setAttribute("oncommand", "su_handle_report_wrong_language_command('" + url + "');");
  13658.         submenu.appendChild(item);
  13659.     }
  13660.  
  13661.     item = document.createElement("menuitem");
  13662.     item.setAttribute("label", " Spam...");
  13663.     item.setAttribute("tooltiptext", "Report this as bad solicitation");
  13664.     item.setAttribute("oncommand", "su_handle_report_spam_command('" + url + "');");
  13665.     submenu.appendChild(item);
  13666.  
  13667.     item = document.createElement("menuitem");
  13668.     item.setAttribute("label", " Unsafe");
  13669.     item.setAttribute("tooltiptext", "Report that this page is a security risk");
  13670.     item.setAttribute("oncommand", "su_handle_report_badware_command('" + url + "');");
  13671.     submenu.appendChild(item);
  13672. }
  13673.  
  13674. function su_prepare_stumble_report_menu(event, url)
  13675. {
  13676.     if (event.originalTarget.id != "su_stumble_report_popup")
  13677.         return;
  13678.     
  13679.     var submenu = su_get_element("su_stumble_report_popup");
  13680.  
  13681.     if (submenu.getAttribute("data-url") == url)
  13682.         return;
  13683.     
  13684.     submenu.removeAttribute("data-url");
  13685.     submenu.setAttribute("data-url", url);
  13686.  
  13687.     // Check if a menu already exists -> If so, we need to remove it
  13688.     var url_detail = su_ds.lookup("url:url_detail", url);
  13689.     
  13690.     while(submenu.childNodes.length)
  13691.         submenu.removeChild(submenu.firstChild);
  13692.     
  13693.     su_prepare_reporting_menu(submenu, url_detail, true, url);
  13694. }
  13695.  
  13696. /*
  13697. // handles discovery dialog accept
  13698. function su_handle_discovery_dialog_accept(detail)
  13699. {
  13700.     if (detail.tagtext != "")
  13701.     {
  13702.         var count = su_ds.getValue("$tagged_discovery_count");
  13703.         count ++;
  13704.         su_ds.setValue("$tagged_discovery_count", count);
  13705.         if (count == 3)
  13706.         {
  13707.             su_ds.setValue("$show_tag", true);
  13708.             su_ds.setValeu("$shown_tag", true);
  13709.             su_ds.setValue("$show_flag", true);
  13710.             su_set_visible("su_tag",  su_ds.getValue("$show_field"));
  13711.             su_set_visible("su_tag2", (! su_ds.getValue("$show_field")));
  13712. //            setTimeout(
  13713. //                        alert,
  13714. //                        500,
  13715. //                        "For convenience, the Tag control has been added to the toolbar.\nIf this is unwelcome, you can remove it via:\ntoolbar->Tools->Toolbar Options.");
  13716.         }
  13717.     }
  13718. }
  13719.  
  13720. // handles discovery dialog cancel
  13721. function su_handle_discovery_dialog_cancel(detail, state)
  13722. {
  13723.     var context = new su_AsyncContext();
  13724.     context.url = detail.rated_uri;
  13725.     context.ref_url = context.url;
  13726.     var params = "url=" + encodeURIComponent(context.url); 
  13727.  
  13728.     params = su_append_sync_params(params);
  13729.  
  13730.     su_post_url_server_async(
  13731.                 "unrate.php",
  13732.                 params,
  13733.                 null,
  13734.                 su_unrate_done,
  13735.                 context);
  13736.  
  13737.     su_check_progress_listener();
  13738. }
  13739. */
  13740.  
  13741. // used by ratingDialog to add a comment
  13742. //function su_add_review(urlid, review)
  13743. //{
  13744. //    su_post_url_server_async(
  13745. //                "addcomment.php",
  13746. //                "urlid=" + urlid + 
  13747. //                    "&comment=" + encodeURIComponent(review),
  13748. //                null,
  13749. //                null,
  13750. //                null);
  13751. //}
  13752.  
  13753. function su_handle_error(error)
  13754. {
  13755.     su_set_server_location('error.php?error=' + error, null, false);
  13756. }
  13757.  
  13758. var su_disabled_button_color = null;
  13759.  
  13760. //
  13761. // Get the color used by the current theme for disabled buttons because we want to
  13762. // use that same color for an active thumbup button (but without disabling it)
  13763. //
  13764. function su_get_disabled_button_color()
  13765. {
  13766.     if(!su_disabled_button_color)
  13767.     {
  13768.         try
  13769.         {
  13770.             // Get the current thumbup state 
  13771.             var elThumbup = su_get_element("su_thumbup");
  13772.             var oldMode = elThumbup.getAttribute("mode");
  13773.             var oldDisabled = elThumbup.disabled;
  13774.             
  13775.             // Disable the button and remove the mode so we can compute the disabled style
  13776.             su_remove_attribute("su_thumbup", "mode");
  13777.             elThumbup.disabled = true;
  13778.             var disabledStyle = document.defaultView.getComputedStyle(elThumbup, "");
  13779.             
  13780.             // Restore the thumbup button to its original state
  13781.             if(oldMode)
  13782.                 elThumbup.setAttribute("mode", oldMode);
  13783.             elThumbup.disabled = oldDisabled;
  13784.             
  13785.             // And grab the disabled button color from the computed stylesheet
  13786.             if(disabledStyle.color)
  13787.             {
  13788.                 su_disabled_button_color = disabledStyle.color;
  13789.             }
  13790.         }
  13791.         catch(ex)
  13792.         {
  13793.             // We are being defensive here because this code is being added late in a release cycle and I'm nervous
  13794.             // about support for getComputedStyle
  13795.         }
  13796.         
  13797.         if(!su_disabled_button_color)
  13798.         {
  13799.             su_disabled_button_color = "GrayText";
  13800.         }
  13801.     }
  13802.     return su_disabled_button_color;
  13803. }
  13804.             
  13805.  
  13806. // Greys out one of the rating buttons
  13807. function su_disable_toolbar(rating)
  13808. {
  13809.     // enable everything first so we don't get su_website_info collisions?
  13810.     
  13811.     su_set_image("su_website_info",
  13812.                 "chrome://stumbleupon/content/skin/comment.png");
  13813.     
  13814.     // We use the disabled color for the thumbup button text when the user has already 
  13815.     // rated the site
  13816.     var disabledColor = su_get_disabled_button_color();
  13817.     su_get_element("su_thumbup").style.color = disabledColor;
  13818.     
  13819.     if (rating > 0)
  13820.     {
  13821.         su_set_attribute("su_thumbup", "mode", "thumbup");
  13822.         su_set_attribute("su_thumbdown", "mode", "thumbup");
  13823.         su_set_image("su_referral_menu", 
  13824.                     "chrome://stumbleupon/content/skin/icon_tb_share2.png");
  13825.     }
  13826.     else
  13827.     {
  13828.         su_set_attribute("su_thumbup", "mode", "thumbdown");
  13829.         su_set_attribute("su_thumbdown", "mode", "thumbdown");
  13830.         su_set_image("su_referral_menu", 
  13831.                     "chrome://stumbleupon/content/skin/icon_tb_share.png");
  13832.     }
  13833.  
  13834.     su_toolbar_disabled = true;
  13835. }
  13836.  
  13837. // Un-greys all the rating buttons
  13838. function su_enable_toolbar()
  13839. {
  13840.     su_toolbar_disabled = false;
  13841.     su_remove_attribute("su_thumbup", "mode");
  13842.     su_get_element("su_thumbup").style.color = '';
  13843.     su_remove_attribute("su_thumbdown", "mode");
  13844.     su_get_element("su_thumbup").disabled = false;
  13845.     su_get_element("su_thumbdown").disabled = false;
  13846.     if (!su_get_element("su_website_info").image.indexOf('bubble'))
  13847.         su_get_element("su_website_info").image="chrome://stumbleupon/content/skin/bubble.png";
  13848.     
  13849.     su_set_image("su_referral_menu", 
  13850.                 "chrome://stumbleupon/content/skin/icon_tb_share.png");
  13851. }
  13852.  
  13853. // called by the global configure-toolbar event, during init and by
  13854. // the searchbox context menuitem listeners to set the autocomplete
  13855. // type for the searchbox
  13856. function su_set_autocomplete_type(type)
  13857. {
  13858.     var oldval = su_ds.getValue("$autocomplete_type");
  13859.     
  13860.     var searchbox = su_get_element('su_searchbox');
  13861.     if ((type == "auto") && (oldval == "query"))
  13862.         type = "query,tag";
  13863.     else if ((type == "auto") && (oldval == "tag"))
  13864.         type = "tag,query";
  13865.     
  13866.     if (type == "query,tag")
  13867.     {
  13868.         searchbox.contextItemAChecked = true;
  13869.         searchbox.contextItemBChecked = false;
  13870.         searchbox.contextItemCChecked = false;
  13871.         su_ds.setValue("$autocomplete_type", "query,tag");
  13872.     }
  13873.     else if (type == "tag,query")
  13874.     {
  13875.         searchbox.contextItemAChecked = true;
  13876.         searchbox.contextItemBChecked = false;
  13877.         searchbox.contextItemCChecked = false;
  13878.         su_ds.setValue("$autocomplete_type", "tag,query");
  13879.     }
  13880.     else if (type == "query")
  13881.     {
  13882.         su_ds.setValue("$autocomplete_type", "query");
  13883.         searchbox.contextItemAChecked = false;
  13884.         searchbox.contextItemBChecked = true;
  13885.         searchbox.contextItemCChecked = false;
  13886.     }
  13887.     else if (type == "tag")
  13888.     {
  13889.         su_ds.setValue("$autocomplete_type", "tag");
  13890.         searchbox.contextItemAChecked = false;
  13891.         searchbox.contextItemBChecked = false;
  13892.         searchbox.contextItemCChecked = true;
  13893.     }
  13894.  
  13895.     if (oldval != type)
  13896.         searchbox.open = false;
  13897. }
  13898.  
  13899. // handles the click event for the searchbox
  13900. function su_searchbox_click_kludge(eventId)
  13901. {
  13902.     // This handles value selection in the case where the user is 
  13903.     // clicking back and forth between the searchbox and another field 
  13904.     // (like urlbar).  Without this kludge, the text is selected only
  13905.     // every second time.  (ref: Firefox 1.5, XP) -- JW
  13906.     
  13907.     switch (eventId)
  13908.     {
  13909.         case "click":
  13910.             var searchbox = su_get_element('su_searchbox');
  13911.             var selected = (searchbox.value.length != 0)
  13912.                         && ((searchbox.selectionEnd - searchbox.selectionStart) == searchbox.value.length);
  13913.  
  13914.             if ((! su_searchbox_was_focused) && (! selected))
  13915.                 searchbox.select();
  13916.             
  13917.             su_searchbox_was_focused = true;
  13918.         break;
  13919.         case "blur":
  13920.             su_searchbox_was_focused = false;
  13921.         break;
  13922.     }
  13923.  
  13924.     return true;
  13925. }
  13926.  
  13927. // handles the focus event for the searchbox
  13928. function su_handle_searchbox_focus(event)
  13929. {
  13930.     var searchbox = su_get_element('su_searchbox');
  13931.  
  13932.     su_visited_searchbox = 1;
  13933.     
  13934.     if (searchbox.value == su_tag_instructions)
  13935.     {
  13936.         searchbox.value = '';
  13937.         searchbox.removeAttribute("mode");
  13938.     }
  13939.     else
  13940.     {
  13941.         if (su_url_has_tag)
  13942.         {    
  13943.             su_old_search = searchbox.value;
  13944.  
  13945.             su_enable_tag_toolbar();
  13946.         }
  13947.         
  13948.         if (! su_keep_searchbox_focus)
  13949.             searchbox.select();
  13950.     }
  13951. }
  13952.  
  13953. // handles the blur event for the searchbox
  13954. function su_handle_searchbox_blur()
  13955. {
  13956.     su_searchbox_click_kludge("blur");
  13957. }
  13958.  
  13959. // handles the keyup event for the searchbox
  13960. function su_handle_searchbox_keyup(evt)
  13961. {
  13962.     var searchbox = su_get_element('su_searchbox');
  13963.  
  13964.     if(searchbox.value == su_old_search)
  13965.         return false;
  13966.     
  13967.     su_old_search = searchbox.value;
  13968.     
  13969.     // save the time we last did this            
  13970.     var da = new Date();
  13971.     su_last_typed_tag = da.getTime();
  13972.  
  13973.     searchbox.removeAttribute("mode");
  13974.     
  13975.     if (su_old_search == "")
  13976.         su_get_element('su_tag').setAttribute("tooltiptext", su_get_element('su_tag').getAttribute("tooltiptext2"));
  13977.     else
  13978.         su_get_element('su_tag').setAttribute("tooltiptext", "Tag this page as '" +     su_get_element('su_searchbox').value + "'");
  13979.  
  13980.     return true;
  13981. }
  13982.  
  13983. // handles the textentered event for the searchbox
  13984. function su_handle_searchbox_textentered(event)
  13985. {
  13986.     var autocomplete_type = su_ds.getValue("$autocomplete_type");
  13987.     if (event.shiftKey)
  13988.     {    
  13989.         if (autocomplete_type == "query,tag")
  13990.             su_ds.setValue("$autocomplete_type", "tag,query");
  13991.         
  13992.         // Shift+Enter tags
  13993.         su_handle_tag_command(false);
  13994.     }
  13995.     else
  13996.     {
  13997.         if (autocomplete_type == "tag,query")
  13998.             su_ds.setValue("$autocomplete_type", "query,tag");
  13999.         
  14000.         su_old_search = su_get_element('su_searchbox').value;
  14001.  
  14002.         // when you search, we know it's not a tag on i-like-it
  14003.         su_last_typed_tag = 0;
  14004.  
  14005.         var new_tab = false;
  14006.         var platform_ctrl_key = (su_host.mac) ? ((event.keyCode == 77) ? event.ctrlKey : event.metaKey) : event.ctrlKey;
  14007.  
  14008.         if ((event.button == 1) || platform_ctrl_key)
  14009.             new_tab = true;
  14010.         new_tab = new_tab || su_ds.getValue("$search_new_window");
  14011.     
  14012.         var query = su_get_element("su_searchbox").value;
  14013.     
  14014.         su_stumble_in_tag(su_get_element('su_searchbox').value, new_tab);    
  14015.     }
  14016. }
  14017.  
  14018. // handles the textreverted event for the searchbox
  14019. function su_handle_searchbox_textreverted()
  14020. {
  14021.     if (su_old_search != "")
  14022.     {
  14023.         su_get_element("su_searchbox").value = su_old_search;
  14024.         su_get_element("su_searchbox").select();
  14025.         su_get_element("su_searchbox").removeAttribute("mode");
  14026.     }
  14027.     else if (su_url_has_tag)
  14028.     {
  14029.         su_disable_tag_toolbar(su_tag_lists_by_url[su_get_browser_url()]);
  14030.     }
  14031. }
  14032.  
  14033. /*
  14034. function su_handle_searchbox_pagenavigationkey(event)
  14035. {
  14036.     su_keep_searchbox_focus = false;
  14037.     su_unfocus_searchbox();
  14038.     setTimeout(function (win, event) { win.su_handle_searchbox_pagenavigationkey_wrapped(event); } , 1000, window, event.keyCode);
  14039. }
  14040.  
  14041. function su_handle_searchbox_pagenavigationkey_wrapped(keyCode)
  14042. {
  14043.     var evt = document.createEvent("KeyboardEvent");
  14044.     evt.initKeyEvent(
  14045.                 "keypress",        //  in DOMString typeArg,
  14046.                 true,             //  in boolean canBubbleArg,
  14047.                 true,             //  in boolean cancelableArg,
  14048.                 null,             //  in nsIDOMAbstractView viewArg,  Specifies UIEvent.view. This value may be null.     
  14049.                 false,            //  in boolean ctrlKeyArg,
  14050.                 false,            //  in boolean altKeyArg,
  14051.                 false,            //  in boolean shiftKeyArg,
  14052.                 false,            //  in boolean metaKeyArg,
  14053.                 keyCode,         //  in unsigned long keyCodeArg,
  14054.                 0);              //  in unsigned long charCodeArg);
  14055.     getBrowser().dispatchEvent(evt);
  14056. //    su_get_element("su_searchbox").focus();
  14057. }
  14058. */
  14059.  
  14060. function su_get_autocomplete_results(autocomplete_type, str, max_item_count, supplemental_candidates)
  14061. {
  14062.     var types = autocomplete_type.split(",");
  14063.     
  14064.     var i;
  14065.     var items = new Array();
  14066.     for (i = 0; i < types.length; i++)
  14067.         items = su_get_autocomplete_results2(types[i], str, max_item_count, items, supplemental_candidates);
  14068.     
  14069.     return items;
  14070. }
  14071.  
  14072. // ultimately called by the searchbox to get an array of items to
  14073. // populate the autocomplete list
  14074. function su_get_autocomplete_results2(autocomplete_type, str, max_item_count, items, supplemental_candidates)
  14075. {
  14076.     // Each array item is an object with properties that are analogous
  14077.     // to attributes of the autocomplete list item.  In other words, 
  14078.     // item.label results in the search widget doing something like:
  14079.     // autocomplete-item.setAttribute("label", item.label);
  14080.     // -- JW
  14081.     
  14082.     // Supplemental candidate matches are placed at the top of the 
  14083.     // results.  Other items are ranked in the autocomplete list in the
  14084.     // same order as they appear in the queries and tags files, which 
  14085.     // is to say in reverse chronological order.  But we may want to 
  14086.     // add a heuristic that places more frequently used tags & queries 
  14087.     // near the top. -- JW
  14088.     var pre_items_count = items.length;
  14089.     var source;
  14090.     var o;
  14091.  
  14092.     if ((str == "") || (str == su_tag_instructions))
  14093.     {
  14094.         // add recent items
  14095.  
  14096.         if (autocomplete_type == "query")
  14097.         {
  14098.             su_load_queries();
  14099.             source = su_queries;
  14100.         }
  14101.         else if (autocomplete_type == "tag")
  14102.         {
  14103.             su_load_tags(null);
  14104.             source = su_tags;
  14105.         }
  14106.  
  14107.         for (var i = (- supplemental_candidates.length); (i < source.length) && (items.length <= max_item_count); i++)
  14108.         {
  14109.             var candidate;
  14110.             if (i < 0)
  14111.             {
  14112.                 candidate = supplemental_candidates[-i - 1];
  14113.             }
  14114.             else
  14115.             {
  14116.                 if (source == su_queries)
  14117.                     candidate = source[i];
  14118.                 else if (source == su_tags)
  14119.                     candidate = source[i].tag_list;
  14120.             }
  14121.                 
  14122.             if (candidate.search(/^\s*$/) != -1)
  14123.                 continue;
  14124.  
  14125.             var duplicate = false;
  14126.             for (var j = 0; j < items.length; j++)
  14127.             {
  14128.                 if (candidate == items[j].label)
  14129.                 {
  14130.                     duplicate = true;
  14131.                     if (j < pre_items_count)
  14132.                         items[j].style = "color:#ff3300;";
  14133.                     break;
  14134.                 }
  14135.             }
  14136.             if (! duplicate)
  14137.             {
  14138.                 o = new Object();
  14139.                 o.label = candidate;
  14140.                 if (autocomplete_type == "tag")
  14141.                     o.style = "color:#ff3300;";
  14142.                 items.push(o);
  14143.             }
  14144.         }
  14145.     }
  14146.     else 
  14147.     {
  14148.         // add the subset of items
  14149.         
  14150.         if (autocomplete_type == "query")
  14151.         {
  14152.             if (str.length == 1)
  14153.                 su_load_queries();
  14154.             source = su_queries;
  14155.         }
  14156.         else if (autocomplete_type == "tag")
  14157.         {
  14158.             if (str.length == 1)
  14159.                 su_load_tags(null);
  14160.             source = su_tags;
  14161.         }
  14162.  
  14163.         str = su_normalize_tag(str);
  14164.         str = su_escape_regexp_chars(str);
  14165.  
  14166.         var pattern = new RegExp("^" + str + "|, " + str, "i");
  14167.  
  14168.         for (var i = (- supplemental_candidates.length); (i < source.length) && (items.length <= max_item_count); i++)
  14169.         {
  14170.             var candidate
  14171.             if (i < 0)
  14172.             {
  14173.                 candidate = supplemental_candidates[-i - 1];
  14174.             }
  14175.             else
  14176.             {
  14177.                 if (source == su_queries)
  14178.                     candidate = source[i];
  14179.                 else if (source == su_tags)
  14180.                     candidate = source[i].tag_list;
  14181.             }
  14182.  
  14183.             if (candidate.search(/^\s*$/) != -1)
  14184.                 continue;
  14185.  
  14186.             if (candidate.search(pattern) != -1)
  14187.             {
  14188.                 
  14189.                 var duplicate = false;
  14190.                 for (var j = 0; j < items.length; j++)
  14191.                 {
  14192.                     if (candidate == items[j].label)
  14193.                     {
  14194.                         duplicate = true;
  14195.                         if (j < pre_items_count)
  14196.                             items[j].style = "color:#ff3300;";
  14197.                         break;
  14198.                     }
  14199.                 }
  14200.                 if (! duplicate)
  14201.                 {
  14202.                     o = new Object();
  14203.                     o.label = candidate;
  14204.                     if (autocomplete_type == "tag")
  14205.                         o.style = "color:#ff3300;";
  14206.                     items.push(o);
  14207.                 }
  14208.             }
  14209.         }
  14210.     }
  14211.     
  14212. //    o = new Object();
  14213. //    o.style = "-moz-binding: url(chrome://global/content/bindings/menu.xml#menuitem-iconic);";
  14214. //    o.image = "chrome://stumbleupon/content/skin/icon_tb_photo_hover.png";
  14215. //    o.label = "Photos";
  14216. //    items.push(o);
  14217.     
  14218.     return items;
  14219.     
  14220. }
  14221.  
  14222. // adds tag to toolbar
  14223. function su_disable_tag_toolbar(tag)
  14224. {
  14225.     if (!su_url_has_tag)
  14226.         su_old_search = su_get_element("su_searchbox").value;
  14227.  
  14228.     su_url_has_tag = true;
  14229.     
  14230.     su_get_element("su_searchbox").value = tag;
  14231.  
  14232.     // This timeout kludge fixes a bug where DOM change events aren't being 
  14233.     // generated when setAttribute is called within the execution path of a
  14234.     // textreverted event handler for the su_searchbox.  (ref: Firefox 1.5, 
  14235.     // XP) -- JW
  14236.     setTimeout('su_get_element("su_searchbox").setAttribute("mode", "tag")', 0);
  14237.  
  14238.     su_get_element("su_tag").image="chrome://stumbleupon/content/skin/tag2.png";
  14239.     su_get_element('su_tag').setAttribute("tooltiptext", "Page tagged as '" + tag + "'. Click to remove.");
  14240.     su_get_element("su_tag2").image="chrome://stumbleupon/content/skin/tag2.png";
  14241.     su_get_element('su_tag2').setAttribute("tooltiptext", "Page tagged as '" + tag + "'. Click to remove.");
  14242. }
  14243.  
  14244. // removes tag from toolbar
  14245. function su_enable_tag_toolbar()
  14246. {
  14247.     su_url_has_tag = false;
  14248.  
  14249.     if (su_visited_searchbox == 0)
  14250.     {
  14251.         su_get_element("su_searchbox").value = su_tag_instructions;
  14252.         su_get_element("su_searchbox").setAttribute("mode", "prompt");
  14253.     }
  14254.     else if (su_old_search != "")
  14255.     {
  14256.         su_get_element("su_searchbox").value = su_old_search;
  14257.         su_get_element("su_searchbox").removeAttribute("mode");
  14258.     }
  14259.     else
  14260.     {
  14261.         su_get_element("su_searchbox").removeAttribute("mode");
  14262.     }
  14263.  
  14264.     su_get_element("su_tag").image="chrome://stumbleupon/content/skin/tag.png";
  14265.     su_get_element("su_tag2").image="chrome://stumbleupon/content/skin/tag.png";
  14266.  
  14267.     if (su_old_search == "")
  14268.     {
  14269.         su_get_element('su_tag').setAttribute("tooltiptext", su_get_element('su_tag').getAttribute("tooltiptext2"));
  14270.         su_get_element('su_tag2').setAttribute("tooltiptext", su_get_element('su_tag2').getAttribute("tooltiptext2"));
  14271.     }
  14272.     else
  14273.     {
  14274.         su_get_element('su_tag').setAttribute("tooltiptext", "Tag this page as '" + su_old_search + "'");
  14275.         su_get_element('su_tag2').setAttribute("tooltiptext", "Tag this page as '" + su_old_search + "'");
  14276.     }
  14277.  
  14278.     return true;
  14279. }
  14280.  
  14281. // su_sign_up_page is the web site's sign up page
  14282. function su_sign_up_page(url)
  14283. {
  14284.     su_visited_login_page = true;
  14285.     su_verify_cookie_perms(false);
  14286.     su_ds.setValue("~visited_signup", true);
  14287.     if (su_is_server_page(url, "sign_up.php?pre2=login"))
  14288.         su_login_behavior_page();
  14289. }
  14290.  
  14291. function su_login_behavior_page()
  14292. {
  14293.     su_visited_login_page = true;
  14294.     setTimeout(su_show_signin_dialog, 0);
  14295. }
  14296.  
  14297. function su_attach_api(doc)
  14298. {
  14299.     try
  14300.     {
  14301.         var win = doc.defaultView.wrappedJSObject;
  14302.         win.suToolbarApi = su_toolbar_api;
  14303.         if(win.onSuToolbarApiReady)
  14304.         {
  14305.             win.onSuToolbarApiReady();
  14306.         }
  14307.     }
  14308.     catch(ex)
  14309.     {
  14310.         // Older browsers might not support wrappedJSObject, be defensive here.
  14311.     }
  14312. }
  14313.  
  14314. function su_wire_portal_links(doc)
  14315. {
  14316.     var el;
  14317.     var links;
  14318.     var i;
  14319.     
  14320.     //!!! This could be pretty expensive on pages with large link count.
  14321.     //    Unfortunately, we link to login.php many places besides the
  14322.     //    header (i.e. a send message error on the public view of
  14323.     //    a Favorites page).
  14324. //    el = doc.getElementById("headerLoginLink");
  14325. //    if (el)
  14326. //        el.addEventListener("click", su_handle_page_login_click, true);
  14327.     
  14328.     el = doc.getElementById("downloadFavoritesLink");
  14329.     if (el)
  14330.         el.addEventListener("click", su_handle_page_favorites_download_click, true);
  14331.     
  14332.     el = doc.getElementById("stumble_search");
  14333.     if (el)
  14334.         el.addEventListener("click", su_handle_page_search_click, true);
  14335. }
  14336.  
  14337. function su_handle_page_login_click(event)
  14338. {
  14339.     setTimeout(su_show_signin_dialog, 0);
  14340.     return su_cancel_event(event);
  14341. }
  14342.  
  14343. function su_handle_page_logout_click(event)
  14344. {
  14345.     if (stumbleid == 0)
  14346.         return true;
  14347.     
  14348.     setTimeout("su_handle_logout(true)", 0);
  14349.     
  14350.     return su_cancel_event(event);
  14351. }
  14352.  
  14353. function su_handle_page_favorites_download_click(event)
  14354. {
  14355.     var ps;
  14356.     
  14357.     if (! su_host.places)
  14358.     {
  14359.         ps = su_get_service(
  14360.                 "@mozilla.org/embedcomp/prompt-service;1",
  14361.                 "nsIPromptService");
  14362.         ps.alert(window, "StumbleUpon", "You must have Firefox 3 or greater to download favorites.");
  14363.         return;
  14364.     }    
  14365.     
  14366.     if (stumbleid == 0)
  14367.     {
  14368.         ps = su_get_service(
  14369.                 "@mozilla.org/embedcomp/prompt-service;1",
  14370.                 "nsIPromptService");
  14371.         ps.confirm(window, "StumbleUpon", "You must be signed-in to download favorites.");
  14372.         return;
  14373.     }
  14374.     
  14375.     setTimeout(su_handle_download_favs_command, 0);
  14376.     
  14377.     return su_cancel_event(event);
  14378. }
  14379.  
  14380. function su_handle_page_search_click(event)
  14381. {
  14382.     var el;
  14383.     var doc = event.target.ownerDocument;
  14384.     
  14385.     el = doc.getElementById("search_q");
  14386.     
  14387.     if (el.value != "")
  14388.         su_stumble_in_tag(el.value, su_new_tab(event));
  14389.     
  14390.     return su_cancel_event(event);
  14391. }
  14392.  
  14393. // su_signup_page is the sign up page that the toolbars sends them to.
  14394. function su_signup_page(doc)
  14395. {
  14396.     su_verify_cookie_perms(false);
  14397.  
  14398.     var el;
  14399.     el = doc.getElementById("interests");
  14400.     if (el)
  14401.         su_set_legacy_user_interests(el.innerHTML);
  14402.     
  14403.     var init_toolbar = (doc.getElementById("signup_success") != null);
  14404.     
  14405.     el = doc.getElementById("challenge");
  14406.     if (el && el.hasAttribute("value") && (el.getAttribute("value") != ""))
  14407.     {
  14408.         su_init_new_user(el.getAttribute("value"), init_toolbar);
  14409.     }
  14410.     else if (init_toolbar)
  14411.     {
  14412.         su_new_user = false;
  14413.         var detail = new Object();
  14414.         detail.skip_cookies = false;
  14415.         detail.ignore_cookies = true;
  14416.         detail.new_profile = true;
  14417.         detail.new_user_prompt = true;
  14418.         su_invoke_global_event("login", detail);
  14419.     }
  14420.     else if (stumbleid != 0)
  14421.     {
  14422.         su_store_user_interests();
  14423.         su_refresh_category_selector_batched();
  14424.     }
  14425. }
  14426.  
  14427. function su_login_page_after()
  14428. {
  14429.     var userid_saved = stumbleid;
  14430.     var profile_change = su_process_cookies(false);
  14431.     
  14432.     if (profile_change && (stumbleid != userid_saved))
  14433.     {
  14434.         var detail = new Object();
  14435.         detail.skip_cookies = true;
  14436.         detail.ignore_cookies = true;
  14437.         detail.new_profile = profile_change.new_profile;
  14438.         detail.new_user_prompt = false;
  14439.         su_invoke_global_event("login", detail);
  14440.     }
  14441. }
  14442.  
  14443. function su_find_friends_page(url)
  14444. {
  14445.     su_ds.setValue("~visited_find_friends", true);
  14446.     var userid_saved = stumbleid;
  14447.     var profile_change = su_process_cookies(false);
  14448.     if (profile_change && (stumbleid != userid_saved))
  14449.     {
  14450.         var detail = new Object();
  14451.         detail.skip_cookies = true;
  14452.         detail.ignore_cookies = true;
  14453.         detail.new_profile = true;
  14454.         detail.new_user_prompt = true;
  14455.         su_invoke_global_event("login", detail);
  14456.     }
  14457.     else
  14458.     {
  14459.         if (su_ds.getValue("#find_friends_optin"))
  14460.         {
  14461.             su_ds.incrementValue("$shown_find_friends_clicks");
  14462.             if ((! su_ds.getValue("$show_searchlinks_score")) &&
  14463.                         (! su_ds.getValue("$show_searchlinks_friends")))
  14464.             {
  14465.                 su_ds.setValue("$show_searchlinks_score", true);
  14466.                 su_ds.setValue("$show_searchlinks_friends", true);
  14467.             }
  14468.             else
  14469.             {
  14470.                 su_ds.setValue("$show_searchlinks_friends", true);
  14471.             }
  14472.             su_ds.setValue("#find_friends_optin", false);
  14473.         }
  14474.     }
  14475.     
  14476.     if (stumbleid)
  14477.         su_ds.setValue("$shown_find_friends", true);
  14478.  
  14479.     su_ds.flushPrefs();
  14480. }
  14481.  
  14482. function su_find_friends_after_page()
  14483. {
  14484.     su_ds.setValue("$shown_find_friends", true);
  14485.     
  14486.     var now_s = su_get_time_s();
  14487.     var pre = su_ds.getValue("#find_friends_pre");
  14488.     if (pre == "facebook")
  14489.         su_ds.setValue("$imported_fbcontacts_time_s", now_s);
  14490.     
  14491.     else
  14492.         su_ds.setValue("$imported_contacts_time_s", now_s);
  14493.     
  14494.     su_ds.setValue("#find_friends_pre", "");
  14495.     
  14496.     su_ds.flushPrefs();
  14497.     setTimeout("su_import_contacts();", 15000);
  14498. }
  14499.  
  14500. function su_stumblevideo_page(doc, from_load)
  14501. {
  14502.     var el = doc.getElementById("url_command");
  14503.  
  14504.     if (! el)
  14505.         return;
  14506.  
  14507.     su_handle_stumblevideo_change(null, doc);
  14508.  
  14509.     el.removeEventListener("DOMAttrModified", su_handle_stumblevideo_change, false);
  14510.     el.addEventListener("DOMAttrModified", su_handle_stumblevideo_change, false);
  14511.     
  14512.     var el2 = doc.getElementById("login_count");
  14513.     if (el2)
  14514.     {
  14515.         el2.removeEventListener("DOMAttrModified", su_handle_stumblevideo_login, false);
  14516.         el2.addEventListener("DOMAttrModified", su_handle_stumblevideo_login, false);
  14517.     }
  14518.     
  14519.     el = doc.getElementById("thumbUp");
  14520.     if (el)
  14521.     {
  14522.         el.removeEventListener("DOMAttrModified", su_handle_stumblevideo_rate, false);
  14523.         el.addEventListener("DOMAttrModified", su_handle_stumblevideo_rate, false)
  14524.     }
  14525.     
  14526.     el = doc.getElementById("thumbDown");
  14527.     if (el)
  14528.     {
  14529.         el.removeEventListener("DOMAttrModified", su_handle_stumblevideo_rate, false);
  14530.         el.addEventListener("DOMAttrModified", su_handle_stumblevideo_rate, false)
  14531.     }
  14532.  
  14533. //    if (su_pending_stumblevideo_stumble)
  14534. //        su_dispatch_click(doc, "stumbleButton");
  14535. //    
  14536. //    su_pending_stumblevideo_stumble = false;
  14537. }
  14538.  
  14539. function su_handle_stumblevideo_login(event)
  14540. {
  14541.     if (event.target.id != "login_count")
  14542.         return true;
  14543.     
  14544.     var userid_saved = stumbleid;
  14545.     var profile_change = su_process_cookies(false);
  14546.     if (profile_change && (stumbleid != userid_saved))
  14547.     {
  14548.         var detail = new Object();
  14549.         detail.skip_cookies = true;
  14550.         detail.ignore_cookies = true;
  14551.         detail.new_profile = profile_change.new_profile;
  14552.         detail.new_user_prompt = false;
  14553.         su_invoke_global_event("login", detail);
  14554.     }
  14555.     return true;
  14556. }
  14557.  
  14558. function su_get_browser_from_doc(doc)
  14559. {
  14560.     var browsers = getBrowser().browsers;
  14561.     var i;
  14562.     var browser = null;
  14563.     for (i = 0; i < browsers.length; i++)
  14564.     {
  14565.         if (browsers[i].contentDocument == doc)
  14566.         {
  14567.             browser = browsers[i];
  14568.             break;
  14569.         }
  14570.     }
  14571.     if (! browser)
  14572.         su_log("MISSING BROWSER");
  14573.     return browser;
  14574. }
  14575.  
  14576. function su_handle_stumblevideo_change(opt_event, opt_doc)
  14577. {
  14578.     su_stumble_async_context = null;
  14579.     su_get_element("su_stumble").image="chrome://stumbleupon/content/skin/stumble.png";
  14580.     var command;
  14581.     var doc;
  14582.     if (opt_event)
  14583.     {
  14584.         if (opt_event.target.id != "url_command")
  14585.             return true;
  14586.         
  14587.         command = opt_event.newValue;
  14588.         doc = opt_event.target.ownerDocument;
  14589.     }
  14590.     else if (opt_doc)
  14591.     {
  14592.         doc = opt_doc;
  14593.         var el = doc.getElementById("url_command");
  14594.         if (! el)
  14595.             return true;
  14596.         
  14597.         if (! el.hasAttribute("value"))
  14598.             return true;
  14599.         
  14600.         command = el.getAttribute("value");
  14601.     }
  14602.  
  14603.     if (command.indexOf("URL ") != 0)
  14604.         return true;
  14605.     
  14606.     var target_browser = su_get_browser_from_doc(doc);
  14607.     if (! target_browser)
  14608.         return true;
  14609.     
  14610.     var overlay_url_detail = su_deserialize_url_command_params(command.substr(4), false);
  14611.     
  14612.     var display_url = su_get_browser_url(doc, true);
  14613.     var url_detail = su_ds.lookup("url:url_detail", display_url);
  14614.     if (url_detail)
  14615.     {
  14616.         url_detail.url = overlay_url_detail.url;
  14617.         url_detail.display_url = display_url;
  14618.     }
  14619.     else
  14620.     {
  14621.         url_detail = overlay_url_detail;
  14622.         url_detail.display_url = display_url;
  14623.     }
  14624.     
  14625.     if (target_browser.su_url_detail &&
  14626.             (url_detail != target_browser.su_url_detail) &&
  14627.             target_browser.su_url_detail.messageid)
  14628.         su_close_message(target_browser.su_url_detail.messageid, true);
  14629.     
  14630.     target_browser.su_url_detail = url_detail; 
  14631.     
  14632. //    su_dd("setstumbled", 2, url_detail.url);
  14633.     stumbled_url = url_detail.url;
  14634.     su_redirect_url = url_detail.url;
  14635.     stumbled_redirect = "";
  14636. //    su_dd("reset", 3);
  14637.     su_refresh_pagemeta(true, 4);
  14638.     
  14639.     return true;
  14640. }
  14641.  
  14642. function su_get_stumblevideo_detail(opt_doc)
  14643. {
  14644.     var browser = null;
  14645.     
  14646.     if (opt_doc)
  14647.     {
  14648.         browser = su_get_browser_from_doc(opt_doc);
  14649.         if (! browser)
  14650.             return null;
  14651.     }
  14652.     else
  14653.     {
  14654.         browser = getBrowser().selectedBrowser;
  14655.     }
  14656.     
  14657.     if (! browser.su_url_detail)
  14658.         return null;
  14659.  
  14660.     var cmp_url = browser.currentURI.asciiSpec;
  14661.     
  14662. //    su_log("svdetail.1");
  14663.     if (! ((cmp_url.indexOf("http://video." + su_servername + "/#p") == 0) ||
  14664.             (cmp_url.indexOf("http://video." + su_servername + "/?p") == 0)))
  14665.         return null;
  14666. //    su_log("svdetail.2");
  14667.     return browser.su_url_detail;
  14668. }
  14669.  
  14670. function su_handle_stumblevideo_rate(opt_event, opt_doc)
  14671. {
  14672.     // Determine the rating
  14673.     var rating = null;
  14674.     var unrate = false;
  14675.     var other_button;
  14676.     var doc;
  14677.     if (opt_event)
  14678.     {
  14679.         var event = opt_event;
  14680.         
  14681.         if (event.attrName != "src")
  14682.             return true;
  14683.     
  14684.         doc = event.target.ownerDocument;
  14685.         
  14686.         if (event.target.id == "thumbUp")
  14687.         {
  14688.             other_button = doc.getElementById("thumbDown");
  14689.             if (event.newValue.indexOf("_sel") != -1)
  14690.                 rating = 1;
  14691.             else if ((event.prevValue.indexOf("_sel") != -1) && 
  14692.                         (event.newValue.indexOf("_sel") == -1) &&
  14693.                         (other_button.src.indexOf("_sel") == -1))
  14694.                 unrate = true;
  14695.         }    
  14696.         else if (event.target.id == "thumbDown")
  14697.         {
  14698.             other_button = doc.getElementById("thumbUp");
  14699.             if (event.newValue.indexOf("_sel") != -1)
  14700.                 rating = 0;
  14701.             else if ((event.prevValue.indexOf("_sel") != -1) && 
  14702.                         (event.newValue.indexOf("_sel") == -1) &&
  14703.                         (other_button.src.indexOf("_sel") == -1))
  14704.                 unrate = true;
  14705.         }
  14706.     }
  14707.     else if (opt_doc)
  14708.     {
  14709.         var doc = opt_doc;
  14710.         var thumbup =     doc.getElementById("thumbUp");
  14711.         var thumbdown = doc.getEementById("thumbDown");
  14712.         if (thumbup && thumbup.src && (thumbup.src.indexOf("_sel") != -1))
  14713.             rating = 1;
  14714.         else if (thumbdown && thumbdown.src && (thumbdown.src.indexOf("_sel") != -1))
  14715.             rating = 0;
  14716.         else if (thumbup && thumbdown && thumbup.src && thumbdown.src &&
  14717.             (thumbup.src.indexOf("_sel") == -1) && (thumbdown.src.indexOf("_sel") == -1))
  14718.             unrate = true;
  14719.     }
  14720.  
  14721.     if (! (unrate || (rating != null)))
  14722.         return true;
  14723.     
  14724.     // Record the rating
  14725.     
  14726.     var url_detail = su_get_stumblevideo_detail(doc);
  14727.     
  14728. //    su_log(1);
  14729.     if (! url_detail)
  14730.     {
  14731.         return true;
  14732.     }
  14733. //    su_log(2);
  14734.     
  14735.     var context = new su_AsyncContext();
  14736.     context.rating = rating;
  14737.     context.url = url_detail.url;
  14738.  
  14739.     if (rating != null)
  14740.     {
  14741.         if (doc == getBrowser().contentDocument)
  14742.             context.browser = getBrowser().selectedBrowser;
  14743.         else
  14744.             contect.browser = null;
  14745.         context.title = null;
  14746.         context.force_nostumble = true;
  14747.         context.force_comment = null;
  14748.         context.timestamp = null;
  14749.         context.open_reviews = null;
  14750.         context.charset = null;
  14751.         context.referrer = null;
  14752.         context.stumblevideo_mode = (su_stumblevideo_toolbar_rate) ? 
  14753.                     "toolbar" : "page";
  14754.     }
  14755.  
  14756.     var res = new Object();
  14757.     res.detail = context;
  14758.     res.status = 200;
  14759.     res.responseText = "";
  14760.     
  14761.     if (context.rating == null)
  14762.     {
  14763.         url_detail.rating = -1;
  14764.         setTimeout(su_unrate_done, 0, res);
  14765.         setTimeout(su_rate_getmeta, 0, context.url, true);
  14766.     }
  14767.     else
  14768.     {
  14769.         url_detail.rating = rating;
  14770.         setTimeout(su_rate_done, 0, res);
  14771.         setTimeout(su_rate_getmeta, 0, context.url, true);
  14772.     }
  14773.     
  14774.     return true;
  14775. }
  14776.  
  14777. function su_rate_getmeta(url, new_rating)
  14778. {
  14779.     if (! su_host.places)
  14780.         return;
  14781.     
  14782.     var params = "";
  14783.     params = su_arp(params, "url", url); 
  14784.     params = su_append_sync_params(params);
  14785.     
  14786.     var context = new su_AsyncContext();
  14787.     context.url = url;
  14788.     context.ref_url = url;
  14789.     context.quiet = true;
  14790.     
  14791.     var loc = (new_rating) ? "getmetanew.php" : "getmetahist.php";
  14792.     
  14793.     su_post_url_server_async(
  14794.                 loc,
  14795.                 params,
  14796.                 null,
  14797.                 su_rate_getmeta_done,
  14798.                 context);
  14799. }
  14800.  
  14801. function su_rate_getmeta_done(res)
  14802. {
  14803.     var context = res.detail;
  14804.     
  14805.     try {
  14806.         if (res.status != 200)
  14807.             return;
  14808.     } catch (e) { return; }
  14809.  
  14810.     var s = "";
  14811.     if (typeof(res.responseText) != "undefined")
  14812.         s = res.responseText;
  14813.     
  14814.     if (su_log_communication)
  14815.         su_log("response " + context.request_target, s);
  14816.     
  14817.     su_process_commands(s, context);
  14818.     
  14819.     su_refresh_pagemeta(false, 8);
  14820. }
  14821.  
  14822. function su_facebook_page(doc, url)
  14823. {
  14824.     if (url.match(/^http.*?\/\/[^\/]*?\.facebook\.com\/home\.php/))
  14825.         su_facebookhome_page(doc);
  14826.     
  14827.     else if (url.match(/^http.*?\/\/[^\/]*?\.facebook\.com\/friends\.php\?r/))
  14828.         su_facebookfriends_page(doc);
  14829.     
  14830.     if (su_ds.getValue("@facebook_user") &&
  14831.                 (su_ds.getValue("@id_list") == "") && 
  14832.                 (! su_ds.getValue("~shown_prompt2")) &&
  14833.                 su_ds.getValue("@enable_prompt2") &&
  14834.                 (! su_ds.getValue("~visited_find_friends")))
  14835.     {
  14836.         su_ds.setValue("~shown_prompt2", true);
  14837.         
  14838.         var detail = new Object();
  14839.         detail.post_url = url;
  14840.         
  14841.         su_show_banner(
  14842.                     "Join StumbleUpon to share you discoveries with your friends on Facebook",
  14843.                     "chrome://stumbleupon/content/skin/stumble.png",
  14844.                     function () { su_handle_prompt_click("prompt2", "accept", detail); },
  14845.                     function () { su_handle_prompt_click("prompt2", "decline", detail); });
  14846.  
  14847. //        var detail = new Object();
  14848. //        detail.target = "prompt2";
  14849. //        detail.post_url = doc.location.toString();
  14850. //        su_show_notifier(
  14851. //                    "Create a StumbleUpon account to see ratings, reviews and recommendations by Facebook friends.",
  14852. //                    "chrome://stumbleupon/content/skin/logo32.png",
  14853. //                    "notifierIcon32",
  14854. //                    5000,
  14855. //                    detail);
  14856.     }
  14857.     
  14858.     var fbuserid = su_get_facebook_userid();
  14859.     if (fbuserid)
  14860.     {
  14861.         su_ds.setValue("#facebook_userid", fbuserid); 
  14862.         su_ds.setValue("#checked_facebook", false);
  14863.         su_ds.setValue("@facebook_user", true);
  14864.     }
  14865. }
  14866.  
  14867. function su_facebookhome_page(doc)
  14868. {
  14869.     if (stumbleid == 0)
  14870.         return;
  14871.     
  14872.     var now_s;
  14873.     var shown_time_s;
  14874.     
  14875.     if (! su_test_facebookhome_prompt)
  14876.     {
  14877.         if (su_ds.getValue("$facebook_added"))
  14878.             return;
  14879.         
  14880.         if (su_ds.getValue("$facebook_homeprompt_optout"))
  14881.             return;
  14882.         
  14883.         if (! su_ds.getValue("@toolbar-visible"))
  14884.             return;
  14885.     
  14886.         now_s = su_get_time_s();
  14887.         shown_time_s = su_ds.getValue("$facebook_homeprompt_time_s"); 
  14888.         
  14889.         if (shown_time_s && ((now_s - shown_time_s) > (2 * 7 * 24 * 60 * 60)))
  14890.             return;
  14891.         
  14892.         if (! su_ds.getValue("#checked_facebook"))
  14893.         {
  14894.             su_get_facebook(doc);
  14895.             return;
  14896.         }
  14897.         
  14898.         if (! su_get_facebook_userid())
  14899.             return;
  14900.     }
  14901.     
  14902.     var target = null;
  14903.     
  14904.     var el = doc.getElementById("home_main");
  14905.     if (! el)
  14906.         return;
  14907.     
  14908.     var hs = el.getElementsByTagName("h2");
  14909.     var i;
  14910.     for (i = 0; i < hs.length; i++)
  14911.     {
  14912.         if (hs[i].innerHTML.indexOf("News Feed") != -1)
  14913.         {
  14914.             target = hs[i];
  14915.             break;
  14916.         }
  14917.     }
  14918.     
  14919.     if (! target)
  14920.         return;
  14921.     
  14922.     if (! target.parentNode)
  14923.         return;
  14924.     
  14925.     var sibling = target.nextSibling;
  14926.     
  14927.     if (sibling != target.parentNode.lastChild)
  14928.         return;
  14929.     
  14930. //    var sibling = sibling.firstChild;
  14931.     
  14932.     if (! sibling)
  14933.         return;
  14934.     
  14935.     var tooltip = "Share websites with friends";
  14936.     
  14937.     var str = "";
  14938.     
  14939.     str += '      ';
  14940.  
  14941.     str += '<a style="text-decoration:none;" title="' + tooltip +
  14942.                 '" href="http://apps.facebook.com/stumbleupon/"><img border="0" width="13" height="13" style="display:inline;position:relative;top:2px;" src="chrome://stumbleupon/content/skin/smallstumble.png"/>  </a><a title="' + tooltip +
  14943.                 '" href="http://apps.facebook.com/stumbleupon/">Add StumbleUpon</a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-c.png"/>';
  14944.     
  14945. //    str += "   <span style="text-size:small;">·</span>   ";
  14946.     
  14947.     el = doc.createElement("span");
  14948.     el.innerHTML = str;
  14949.     el.setAttribute("style", "float:left;");
  14950.     
  14951.     sibling.parentNode.insertBefore(el, sibling);
  14952.     
  14953.     el.lastChild.addEventListener("click", su_handle_facebook_homeprompt_optout_click, false);
  14954.  
  14955.     if (! su_test_facebookhome_prompt)
  14956.     {
  14957.         if (! shown_time_s)
  14958.             su_ds.setValue("$facebook_homeprompt_time_s", now_s);
  14959.     }
  14960. }
  14961.  
  14962. function su_handle_searchpageprompt_optout_click(event)
  14963. {
  14964.     su_handle_prompt_optout_click(event, "search");
  14965. }
  14966.  
  14967. function su_handle_facebook_homeprompt_optout_click(event)
  14968. {
  14969.     su_handle_prompt_optout_click(event, "fbhome");
  14970. }
  14971.  
  14972. function su_handle_prompt_optout_click(event, promptid)
  14973. {
  14974.     var ps = su_get_service(
  14975.                 "@mozilla.org/embedcomp/prompt-service;1",
  14976.                 "nsIPromptService");
  14977.     var out = ps.confirmEx(
  14978.                 window,
  14979.                 "StumbleUpon Confirm",
  14980.                 "Do you want to permanently remove this StumbleUpon link?",
  14981.                 ps.STD_YES_NO_BUTTONS,
  14982.                 null,
  14983.                 null,
  14984.                 null,
  14985.                 null,
  14986.                 {});
  14987.     if (out == 0)
  14988.     {
  14989.         switch (promptid)
  14990.         {
  14991.             case "fbhome":
  14992.                 var target = event.target.parentNode;
  14993.                 target.parentNode.removeChild(target);
  14994.                 su_ds.setValue("$facebook_homeprompt_optout", true);
  14995.                 break;
  14996.             case "search":
  14997.                 var target = event.target.parentNode;
  14998.                 target.parentNode.removeChild(target);
  14999.                 su_ds.setValue("$shown_find_friends_optout", true);
  15000.                 break;
  15001.         }
  15002.     }
  15003. }
  15004.  
  15005. function su_facebookfriends_page(doc)
  15006. {
  15007.     if (! su_ds.getValue("@toolbar-visible"))
  15008.         return;
  15009.     
  15010.     var el = doc.getElementById("friendtables");
  15011.     if (! el)
  15012.         return;
  15013.     var as = el.getElementsByTagName("a");
  15014.     var targets = new Array();
  15015.     var userids = new Array();
  15016.     for (i = 0; i < as.length; i++)
  15017.     {
  15018.         var match = as.item(i).href.match(/http\:\/\/[^\/]*\.facebook\.com\/addfriend\.php\?id=(.*)/);
  15019.  
  15020.         if (! match)
  15021.             match = as.item(i).href.match(/http\:\/\/[^\/]*\.facebook\.com\/friends\.php\?remove_friend=1\&friend_id=(.*)/);
  15022.         
  15023.         if (! match)
  15024.             continue;
  15025.  
  15026.         var target = as.item(i).parentNode;
  15027.         
  15028.         if (! target)
  15029.             continue;
  15030.         
  15031.         if (target.className != "actions")
  15032.             continue;
  15033.         
  15034.         userids.push(match[1]);
  15035.         targets.push(target);
  15036.     }
  15037.     
  15038.     if (userids.length == 0)
  15039.         return;
  15040.     
  15041.     
  15042.     // su_check_facebook_contacts(userids, targets);
  15043. }
  15044.  
  15045. /*
  15046. function su_check_facebook_contacts(fb_userids, targets)
  15047. {
  15048.     var i;
  15049.     var contact;
  15050.     var contacts = su_ds.selectAllRows("contact");
  15051.     var contacts_by_fbid = new Object();
  15052.     var now_s = su_get_time_s();
  15053.     var checked_time_s = su_ds.getValue("$facebook_contacts_time_s"); 
  15054.     var refresh_cache = (checked_time_s && ((now_s - checked_time_s) > (18 * 60 * 60)));
  15055.     var anonymize_nonmutuals = refresh_cache;
  15056.  
  15057.     for (i = 0; i < contacts.length; i++)
  15058.     {
  15059.         contact = contacts[i];
  15060.         if (contact.fbid)
  15061.         {
  15062.             contacts_by_fbid[contact.fbid] = contact;
  15063.             if (anonymize_nonmutuals && contact.contactid && (! contact.mutual))
  15064.             {
  15065.                 contact.contactid = "";
  15066.                 contact.nickname = "";
  15067.                 su_ds.updateRow(contact);
  15068.             }
  15069.         }
  15070.     }
  15071.     
  15072.     for (i = 0; i < fb_userids.length; i++)
  15073.     {
  15074.         if (contacts_by_fbid[fb_userids[i]])
  15075.             contact
  15076.         
  15077.         var contactid = friends[i].split(".")[0];
  15078.         var nickname = friends[i].split(".")[1];
  15079.         var facebookid = friends[i].split(".")[2];
  15080.         
  15081.         fbfriends[contactid] = true;
  15082.  
  15083.         contact = null;
  15084.         
  15085.         if (contacts_by_id[contactid])
  15086.             contact = contacts_by_id[contactid];
  15087.         
  15088.         if (contact)
  15089.         {
  15090.             contact.nickname = nickname;
  15091.             contact.fbid = facebookid;
  15092.             su_ds.updateRow(contact);
  15093.         }
  15094.         else
  15095.         {
  15096.             contact = new Object();
  15097.             contact.contactid = contactid;
  15098.             contact.nickname = nickname;
  15099.             contact.fbid = facebookid;
  15100.             su_ds.insertRow("contact", contact);
  15101.             contacts_by_id[contactid] = contact;
  15102.         }
  15103.     }
  15104.  
  15105.     for (i = 0; i < contacts.length; i++)
  15106.     {
  15107.         if ((typeof (contacts[i].contactid)) != "undefined")
  15108.         {
  15109.             if (contacts[i].fbid && (! fbfriends[contacts[i].contactid]))
  15110.                 contacts[i].fbid = 0;
  15111.             
  15112.             su_ds.updateRow(contacts[i]);
  15113.         }
  15114.     }
  15115.     
  15116.     if (userids)
  15117.     {
  15118.         
  15119.     }
  15120.     
  15121. }
  15122. */
  15123.  
  15124. function su_search_results_page(doc, service_id)
  15125. {
  15126.     su_search_service_page(doc, service_id);
  15127.     su_augment_links(doc, service_id);
  15128. }
  15129.  
  15130. function su_search_service_page(doc, service_id)
  15131. {
  15132.     var now_s;
  15133.     var shown_time_s;
  15134.     if (! su_test_searchpage_prompt)
  15135.     {
  15136.         if (! su_ds.hasFeature("$sociallinks"))
  15137.             return;
  15138.         
  15139.         if (! su_ds.getValue("@toolbar-visible"))
  15140.             return;
  15141.         
  15142.         if (su_ds.getValue("$imported_contacts_time_s"))
  15143.             return;
  15144.         
  15145.         if (su_ds.getValue("$shown_find_friends_optout"))
  15146.             return;
  15147.         
  15148. //        if ((! su_ds.hasFeature("$unlimitedslpromptclicks") &&
  15149. //                    (su_ds.getValue("$shown_find_friends_clicks") >= 3)))
  15150. //            return;
  15151.     
  15152.         now_s = su_get_time_s();
  15153.         shown_time_s = su_ds.getValue("$shown_find_friends_time_s"); 
  15154.     
  15155.         if (shown_time_s && ((now_s - shown_time_s) > (3 * 7 * 24 * 60 * 60)))
  15156.             return;
  15157.     }
  15158.     
  15159.     var tooltip = "Add StumbleUpon friends to see which search results they prefer";
  15160.     var str = '<a style="text-decoration:none;" title="' + 
  15161.                 tooltip + '" href="' + su_serverhttp + 
  15162.                 'find_friends.php?pre3=' + service_id + '">';
  15163.     
  15164.     if (su_ds.getValue("$show_searchlinks_logo"))
  15165.         str += '<img border="0" width="13" height="13" style="display:inline;position:relative;top:1px;" src="http://cdn.stumble-upon.com/images/embed/smallstumble.png"> <u style="position:relative;top:-1px;">See friend reviews</u></a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-c.png"/>';
  15166.     else
  15167.         str += '<u>See StumbleUpon friend reviews</u></a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-c.png"/>';
  15168.     
  15169.     switch (service_id)
  15170.     {
  15171. //        case "google":
  15172. //            str = " " + str;
  15173. //            var target = null;
  15174. //            var el = doc.getElementById("gbar");
  15175. //            if (! el)
  15176. //                return;
  15177. //            var us = el.getElementsByTagName("u");
  15178. //            var i;
  15179. //            for (i = 0; i < us.length; i++)
  15180. //            {
  15181. //                if (us[i].innerHTML == "more")
  15182. //                {
  15183. //                    target = us[i];
  15184. //                    break;
  15185. //                }
  15186. //            }
  15187. //            if (! target)
  15188. //                return;
  15189. //            
  15190. //            target = target.parentNode;
  15191. //            
  15192. //            if (! target)
  15193. //                return;
  15194. //            
  15195. //            target = target.parentNode;
  15196. //            
  15197. //            if (! target)
  15198. //                return;
  15199. //
  15200. //            target = target.nextSibling;
  15201. //            
  15202. //            if (! target)
  15203. //                return;
  15204. //        
  15205. //            if (! target.parentNode)
  15206. //                return;
  15207. //            
  15208. //            el = doc.createElement("span");
  15209. //            el.innerHTML = str;
  15210. //            
  15211. //            target.parentNode.insertBefore(el, target);
  15212. //            el.lastChild.addEventListener("click", su_handle_searchpageprompt_optout_click, false);
  15213. //            break;
  15214.         case "google":
  15215.         case "google-ajax":
  15216.         case "googlenews":
  15217.             // Add listeners for results that are populated by Ajax.
  15218.             if(service_id == "google-ajax")
  15219.             {
  15220.                 // Google classic uses ajax to populate the search results, so we need to do 
  15221.                 // our augmentation work when the results are all inserted, which is whenever the xfoot
  15222.                 // element is inserted.
  15223.                 if(!doc.__su__listening_ff)
  15224.                 {
  15225.                     doc.__su__listening_ff = true;
  15226.                     doc.addEventListener("DOMNodeInserted", function(event) {
  15227.                         if(event.target.id == "xfoot")
  15228.                         {
  15229.                             if(!doc.getElementById("__su__service_ff"))
  15230.                             {
  15231.                                 su_search_service_page(doc, service_id);
  15232.                             }
  15233.                         }
  15234.                     }, false);
  15235.                 }
  15236.             }
  15237.             var el = doc.getElementById("gbar");
  15238.             if (! el)
  15239.                 return;
  15240.             var us = el.getElementsByTagName("u");
  15241.             var target = null;
  15242.             var i;
  15243.             for (i = 0; i < us.length; i++)
  15244.             {
  15245.                 if (us[i].innerHTML == "more")
  15246.                 {
  15247.                     target = us[i];
  15248.                     break;
  15249.                 }
  15250.             }
  15251.             if (! target)
  15252.                 return;
  15253.             
  15254.             target = target.parentNode;
  15255.             
  15256.             if (! target)
  15257.                 return;
  15258.             
  15259. //            target = target.parentNode;
  15260.             
  15261. //            if (! target)
  15262. //                return;
  15263.         
  15264.             if (! target.parentNode)
  15265.                 return;
  15266.             
  15267.             el = doc.createElement("td");
  15268.             el.id = "__su__service_ff";
  15269.             el.setAttribute("nowrap", "nowrap");
  15270.             el.innerHTML = str;
  15271.             target.parentNode.appendChild(el);
  15272.             el.lastChild.addEventListener("click", su_handle_searchpageprompt_optout_click, false);
  15273.             break;
  15274.         case "googleindex":
  15275.         case "googlevideo":
  15276.             var el = doc.getElementById("gbar");
  15277.             if (! el)
  15278.                 return;
  15279.             var us = el.getElementsByTagName("u");
  15280.             var target = null;
  15281.             var i;
  15282.             for (i = 0; i < us.length; i++)
  15283.             {
  15284.                 if (us[i].innerHTML == "more")
  15285.                 {
  15286.                     target = us[i];
  15287.                     break;
  15288.                 }
  15289.             }
  15290.             if (! target)
  15291.                 return;
  15292.             
  15293.             target = target.parentNode;
  15294.             
  15295.             if (! target)
  15296.                 return;
  15297.             
  15298.             target = target.parentNode;
  15299.             
  15300.             if (! target)
  15301.                 return;
  15302.         
  15303.             if (! target.parentNode)
  15304.                 return;
  15305.             
  15306.             el = doc.createElement("td");
  15307.             el.setAttribute("nowrap", "nowrap");
  15308.             el.innerHTML = str;
  15309.             target.parentNode.appendChild(el);
  15310.             el.lastChild.addEventListener("click", su_handle_searchpageprompt_optout_click, false);
  15311.             break;
  15312.         case "yahoo":
  15313.             str = '    <a style="text-decoration:none;" title="' + 
  15314.                         tooltip + '" href="' + su_serverhttp + 
  15315.                         'find_friends.php?pre3=' + service_id + '">';
  15316.                         
  15317.             if (su_ds.getValue("$show_searchlinks_logo"))
  15318.                 str += '<img border="0" width="13" height="13" style="display:inline;position:relative;top:2px;" src="http://cdn.stumble-upon.com/images/embed/smallstumble.png"> <u style="color:rgb(21,73,193);">See friend reviews</u></a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-c.png"/>';
  15319.             else
  15320.                 str += '<u style="color:rgb(21,73,193);">See StumbleUpon friend reviews</u></a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-c.png"/>';
  15321.     
  15322.             var target = doc.getElementById("tabs");
  15323.             var style = "white-space:nowrap;position:relative;top:-1px;"
  15324.             if (! target)
  15325.             {
  15326.                 target = doc.getElementById("eb");
  15327.                 style = "white-space:nowrap;position:relative;top:-2px;";
  15328.             }
  15329.             if (! target)
  15330.                 return;
  15331.             target.setAttribute("style", "white-space:nowrap;");
  15332.             var el = doc.createElement("span");
  15333.             el.setAttribute("style", style);
  15334.             el.innerHTML = str;
  15335.             target.appendChild(el);
  15336.             el.lastChild.addEventListener("click", su_handle_searchpageprompt_optout_click, false);
  15337.             break;
  15338.         case "ask":
  15339.             str = '  <a style="text-decoration:none;" title="' + 
  15340.                         tooltip + '" href="' + su_serverhttp + 
  15341.                         'find_friends.php?pre3=' + service_id + '">';
  15342.                 
  15343.             if (su_ds.getValue("$show_searchlinks_logo"))
  15344.                 str += '<img border="0" width="13" height="13" style="display:inline;position:relative;top:1px;" src="http://cdn.stumble-upon.com/images/embed/smallstumble.png"> <span style="color:blue;">See friend reviews</span></a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-d.png"/>';
  15345.             else
  15346.                 str += '<span style="color:blue;">See StumbleUpon friend reviews</span></a> <img border="0" width="13" height="12" style="display:inline;cursor:pointer;" src="chrome://stumbleupon/content/skin/close-d.png"/>';
  15347.             var target = doc.getElementById("navbar_tabs");
  15348.             if (! target)
  15349.                 return;
  15350.             var el = doc.createElement("span");
  15351.             el.innerHTML = str;
  15352.             target.appendChild(el);
  15353.             el.lastChild.addEventListener("click", su_handle_searchpageprompt_optout_click, false);
  15354.             break;
  15355.         case "aol":
  15356.             var target = doc.getElementById("morecsb");
  15357.             if (! target)
  15358.                 return;
  15359.             target = target.parentNode;
  15360.             if (! target)
  15361.                 return;
  15362.             target = target.parentNode;
  15363.             if (! target)
  15364.                 return;
  15365.             var el = doc.createElement("span");
  15366.             el.innerHTML = str;
  15367.             target.appendChild(el);
  15368.             el.lastChild.addEventListener("click", su_handle_searchpageprompt_optout_click, false);
  15369.             break;
  15370.     }
  15371.     if (! su_test_searchpage_prompt)
  15372.     {
  15373.         if (! shown_time_s)
  15374.             su_ds.setValue("$shown_find_friends_time_s", now_s);
  15375.     }
  15376. }
  15377.     
  15378. // extracts links from a page and calls links.php
  15379. function su_augment_links(doc, service_id)
  15380. {
  15381.     if ((! su_ds.getValue("$show_searchlinks_score")) &&
  15382.                 (! su_ds.getValue("$show_searchlinks_friends")) &&
  15383.                 (! su_ds.getValue("$show_searchlinks_topic")))
  15384.         return;
  15385.  
  15386.     if (! su_ds.getValue("@toolbar-visible"))
  15387.         return;
  15388.     
  15389.     var as;
  15390.     var target;
  15391.     var el;
  15392.     switch (service_id)
  15393.     {
  15394.         
  15395.         case "wikipedia":
  15396.             el = doc.getElementById("top");
  15397.             while (el)
  15398.             {
  15399.                 if (el.className == "firstHeading")
  15400.                     break;
  15401.                 el = el.nextSibling;
  15402.             }
  15403.             if (! el)
  15404.                 return;
  15405.             var title = el;
  15406.             var title_text = title.innerHTML;
  15407.             title.innerHTML = "";
  15408.             var inline = doc.createElement("span");
  15409.             title.appendChild(inline);
  15410.             target = doc.createElement("span");
  15411.             target.innerHTML = title_text;
  15412.             inline.appendChild(target);
  15413.             break;
  15414.         case "cnn":
  15415.             var el = doc.getElementById("cnnSearchResults");
  15416.             if (! el)
  15417.                 return;
  15418.             as = el.getElementsByTagName("a");
  15419.             break;
  15420.         default:
  15421.             as = doc.getElementsByTagName("a");
  15422.             break;
  15423.     }
  15424.     var urls = new Array();
  15425.     var targets = new Array();
  15426.     var hrefs = urls;
  15427.     var i;
  15428.     
  15429.     var linked_color = "rgb(130, 132, 204)";
  15430.     var unlinked_color = "rgb(0, 0, 0)";
  15431.     var underline = true;
  15432.     var font_size = "100%";
  15433.     var force_no_logo = false;
  15434.     var force_inline = false;
  15435.     var soft_wrap = false;
  15436.     var hard_wrap = false;
  15437.     var force_logo = false;
  15438.     var before_targets = targets;
  15439.     var after_targets = targets;
  15440.     var include_topic = false;
  15441.     var image_baseline = false;
  15442.     var enable_click_tracking = true;
  15443.     
  15444.     // Check whether we need to add listeners for results that are populated by Ajax.
  15445.     if( (service_id == "google-ajax") ||
  15446.         (service_id == "googlevideo") )
  15447.     {
  15448.         // Google classic uses ajax to populate the search results, so we need to do 
  15449.         // our augmentation work when the results are all inserted, which is whenever the xfoot
  15450.         // element is inserted.
  15451.         var idlast = "";
  15452.         if(service_id == "google-ajax")
  15453.         {
  15454.             idlast = "xfoot";
  15455.         }
  15456.         else if(service_id == "googlevideo")
  15457.         {
  15458.             idlast = "pagi";
  15459.         }
  15460.         if(!doc.__su__listening)
  15461.         {
  15462.             doc.__su__listening = true;
  15463.             doc.addEventListener("DOMNodeInserted", function(event) {
  15464.                 if(event.target.id == idlast)
  15465.                 {
  15466.                     su_augment_links(doc, service_id);
  15467.                 }
  15468.             }, false);
  15469.         }
  15470.     }
  15471.     
  15472.     switch (service_id)
  15473.     {
  15474.         case "google-ajax":
  15475.         case "google":
  15476.             after_targets = new Array();
  15477.             linked_color = "#7777cc";
  15478.             unlinked_color = linked_color;
  15479.             font_size = "smaller";
  15480.             for (i = 0; i < as.length; i++)
  15481.             {
  15482.                 if (as.item(i).className == "l")
  15483.                 {
  15484.                     if (as.item(i).firstChild && (as.item(i).firstChild.tagName == "IMG") &&
  15485.                                 (as.item(i).firstChild.src.indexOf("/mapfiles/") != -1))
  15486.                         continue; // at top
  15487.                     
  15488.                     var redir_match = as.item(i).href.match(/^http.*?\/\/[^\/]*?(google\.[^\.]+|google\.co\.[^\.]+)\/(url.*[?&]q=)([^&]+)/);
  15489.                     if (redir_match && redir_match.length >= 4)
  15490.                         urls.push(decodeURIComponent(redir_match[3]));
  15491.                     else
  15492.                         urls.push(as.item(i).href);
  15493.                     targets.push(as.item(i));
  15494.                     if (as.item(i).parentNode.nextSibling && as.item(i).parentNode.nextSibling.tagName == "FONT" && as.item(i).parentNode.nextSibling.firstChild && as.item(i).parentNode.className != "r")
  15495.                         after_targets.push(as.item(i).parentNode.nextSibling.firstChild);
  15496.                     else
  15497.                         after_targets.push(as.item(i));
  15498.                 }
  15499.             }
  15500.             break;
  15501.         case "googlenews":
  15502.         case "googlenewsindex":
  15503.             after_targets = new Array();
  15504.             enable_click_tracking = su_ds.hasFeature("$newsclicktracking");
  15505.             linked_color = "#7777cc";
  15506.             unlinked_color = linked_color;
  15507.             font_size = "smaller";
  15508.             for (i = 0; i < as.length; i++)
  15509.             {
  15510.                 if (as.item(i).parentNode.className == "title")
  15511.                 {
  15512.                     if (as.item(i).href.indexOf("http://news.google.co") == 0)
  15513.                         continue;
  15514.                     urls.push(as.item(i).href);
  15515.                     targets.push(as.item(i));
  15516.                     after_targets.push(as.item(i));
  15517.                 }
  15518.             }
  15519.             break;
  15520.         case "googlevideo":
  15521.             linked_color = "#7777cc";
  15522.             font_size = "small";
  15523.             force_logo = su_ds.getValue("$show_searchlinks_logo");
  15524.             hrefs = new Array();
  15525.             for (i = 0; i < as.length; i++)
  15526.             {
  15527.                 var anchor = as.item(i);
  15528.                 if (anchor.parentNode.className == "rl-title")
  15529.                 {
  15530.                     urls.push(anchor.href);
  15531.                     targets.push(anchor);
  15532.                 }
  15533.             }
  15534.             break;
  15535.         case "ask":
  15536.             linked_color = "auto";
  15537.             for (i = 0; i < as.length; i++)
  15538.             {
  15539.                 if (as.item(i).className == "L4")
  15540.                 {
  15541.                     var matches = as.item(i).href.match(/&u=([^&]*)/);
  15542.                     if(matches && matches[1])
  15543.                     {
  15544.                         urls.push(decodeURIComponent(matches[1]));
  15545.                     }
  15546.                     else
  15547.                     {
  15548.                         urls.push(as.item(i).href);
  15549.                     }
  15550.                     targets.push(as.item(i));
  15551.                 }
  15552.             }
  15553.             break;
  15554.         case "bing":
  15555.             var h3s = doc.getElementsByTagName("h3");
  15556.             for (var i = 0; i < h3s.length; i++)
  15557.             {
  15558.                 var anchors = h3s[i].getElementsByTagName("a");
  15559.                 if (anchors.length == 1)
  15560.                 {
  15561.                     var a = anchors[0];
  15562.                     urls.push(a.href);
  15563.                     targets.push(a);
  15564.                 }
  15565.             }
  15566.             break;
  15567.         case "bing-news":
  15568.             var headlines = doc.getElementsByClassName("Headline");
  15569.             for (var i = 0; i < headlines.length; i++)
  15570.             {
  15571.                 var anchors = headlines[i].getElementsByTagName("a");
  15572.                 if (anchors.length == 1)
  15573.                 {
  15574.                     var a = anchors[0];
  15575.                     urls.push(a.href);
  15576.                     targets.push(a);
  15577.                 }
  15578.             }
  15579.             break;
  15580.         case "nyt":
  15581.             force_inline = true;
  15582.             var h3s = doc.getElementsByTagName("h3");
  15583.             for (var i = 0; i < h3s.length; i++)
  15584.             {
  15585.                 var anchors = h3s[i].getElementsByTagName("a");
  15586.                 if (anchors.length == 1)
  15587.                 {
  15588.                     var href = anchors[0].href;
  15589.                     // They include search referral and search term information at the end of the URL, 
  15590.                     // past the ?scp=, so we strip that out if it exists.
  15591.                     var match = href.match(/(.*?)(\?scp=.*)/);
  15592.                     if(match)
  15593.                     {
  15594.                         href = match[1];
  15595.                     }
  15596.                     urls.push(href);
  15597.                     targets.push(anchors[0]);
  15598.                 }
  15599.             }
  15600.             break;
  15601.         case "yahoo":
  15602.             // Yahoo changes the href with global script, so we have to wait for
  15603.             // the "load" event at which point the href will have been set to the final URL.
  15604.             if(!doc.__su__listening)
  15605.             {
  15606.                 doc.__su__listening = true;
  15607.                 doc.defaultView.addEventListener("load", function(event) {
  15608.                     if(event.target.__su__listening)
  15609.                     {
  15610.                         su_augment_links(doc, service_id);
  15611.                     }
  15612.                 }, false);
  15613.                 return;
  15614.             }
  15615.             
  15616.             // We got back in here from the load event, now do our work.
  15617.             soft_wrap = true;
  15618.             hrefs = new Array();
  15619.             for (i = 0; i < as.length; i++)
  15620.             {
  15621.                 if ((as.item(i).className.indexOf("yschttl") != -1) )// && as.item(i).href.match(/\*\*(.*)/))
  15622.                 {
  15623.                     var href = as.item(i).href;
  15624.                     var match = href.match(/http\:\/\/rds.yahoo.com.*?\*\*(.*)/);
  15625.                     if(match && match[1])
  15626.                     {
  15627.                         href = decodeURIComponent(match[1]);
  15628.                     }
  15629.                     urls.push(href);
  15630.                     hrefs.push(href);
  15631.                     targets.push(as.item(i));
  15632.                 }
  15633.             }
  15634.             break;
  15635.         case "aol":
  15636.             font_size = "larger";
  15637.             hrefs = new Array();
  15638.             for (i = 0; i < as.length; i++)
  15639.             {
  15640.                 if (as.item(i).className == "find")
  15641.                 {
  15642.                     hrefs.push(as.item(i).href);
  15643.                     urls.push(as.item(i).href);
  15644.                     targets.push(as.item(i));
  15645.                 }
  15646.             }
  15647.             break;
  15648.         case "myspace":
  15649.             for (i = 0; i < as.length; i++)
  15650.             {
  15651.                 var anchor = as.item(i);
  15652.                 if( anchor.parentNode &&
  15653.                     anchor.parentNode.parentNode &&
  15654.                     (anchor.parentNode.parentNode.className.indexOf("searchResults") != -1) )
  15655.                 {
  15656.                     urls.push(anchor.href);
  15657.                     targets.push(anchor);
  15658.                 }
  15659.             }
  15660.             break;
  15661.         case "youtube":
  15662.             underline = false;
  15663.             soft_wrap = true;
  15664.             font_size = "small";
  15665.             for (i = 0; i < as.length; i++)
  15666.             {
  15667.                 if (as.item(i).id.indexOf("video-long-title") == 0)
  15668.                 {
  15669.                     urls.push(as.item(i).href);
  15670.                     targets.push(as.item(i));
  15671.                 }
  15672.             }
  15673.             break;
  15674.         case "wikipedia":
  15675.             font_size = "small";
  15676.             underline = false;
  15677.             image_baseline = true;
  15678.             // include_topic = true;
  15679.             enable_click_tracking = su_ds.hasFeature("$titleclicktracking");
  15680.             urls.push(doc.location.href);
  15681.             targets.push(target);
  15682.             break;
  15683.         case "flickr":
  15684.             underline = false;
  15685.             hard_wrap = true;
  15686.             soft_wrap = true;
  15687.             linked_color = "auto";
  15688.             font_size = "small";
  15689.             for (i = 0; i < as.length; i++)
  15690.             {
  15691.                 var anchor = as.item(i);
  15692.                 var ancestor = su_get_ancestor_by_prop_value(anchor,
  15693.                             "className", "ResultsThumbsChild", 4);
  15694.                 if (ancestor && anchor.firstChild && 
  15695.                     anchor.firstChild.className &&
  15696.                     (anchor.firstChild.className.indexOf("pc_img") != -1))
  15697.                 {
  15698.                     urls.push(anchor.href);
  15699.                     targets.push(anchor);
  15700.                 }
  15701.             }
  15702.             break;
  15703.         case "cnn":
  15704.             for (i = 0; i < as.length; i++)
  15705.             {
  15706.                 if (as[i].className == "cnnSearchResultsHeadline")
  15707.                 {
  15708.                     var redir_match = as.item(i).href.match(/arProcessing\.jsp.*?[?&]dest=([^?&]+)/);
  15709.                     if (redir_match && redir_match.length >= 0)
  15710.                         urls.push(redir_match[1]);
  15711.                     else
  15712.                         urls.push(as.item(i).href);
  15713.                     targets.push(as.item(i));
  15714.                 }
  15715.             }
  15716.             break;
  15717.         case "cbsnews":
  15718.             for (i = 0; i < as.length; i++)
  15719.             {
  15720.                 if (as.item(i).className == "storyTitle")
  15721.                 {
  15722.                     urls.push(as.item(i).href);
  15723.                     targets.push(as.item(i));
  15724.                 }
  15725.             }
  15726.             break;
  15727.         case "cnetnews":
  15728.             force_inline = true;
  15729.             for (i = 0; i < as.length; i++)
  15730.             {
  15731.                 if (as.item(i).className == "resultName")
  15732.                 {
  15733.                     urls.push(as.item(i).href);
  15734.                     targets.push(as.item(i));
  15735.                 }
  15736.             }
  15737.             break;
  15738.         case "abcnews":
  15739.             for (i = 0; i < as.length; i++)
  15740.             {
  15741.                 if (as.item(i).className == "title")
  15742.                 {
  15743.                     urls.push(as.item(i).href);
  15744.                     targets.push(as.item(i));
  15745.                 }
  15746.             }
  15747.             break;
  15748.         case "msnbc":
  15749.             for (i = 0; i < as.length; i++)
  15750.             {
  15751.                 var anchor = as.item(i);
  15752.                 if(anchor.parentNode.tagName == "H4")
  15753.                 {
  15754.                     urls.push(anchor.href);
  15755.                     targets.push(anchor);
  15756.                 }
  15757.             }
  15758.             break;
  15759.     }
  15760.     
  15761.     if (urls.length == 0)
  15762.         return;
  15763.     
  15764.     var url = su_get_browser_url(doc);
  15765.     
  15766.     var query_detail = su_get_search_query_detail(service_id, url);
  15767.     
  15768.     var now = (new Date()).getTime();
  15769.     
  15770.     var slstats = new Object();
  15771.     slstats.timestamp = now;
  15772.     slstats.slq = 0;
  15773.     slstats.term_count = query_detail.term_count;
  15774.     slstats.url_count = hrefs.length;
  15775.     slstats.decorated_count = 0;
  15776.     slstats.first_decorated_num = 0;
  15777.  
  15778.     if (enable_click_tracking)
  15779.     {
  15780.         su_ds.globals.sls.push(slstats);
  15781.         var slq = su_ds.globals.sls.length;
  15782.         slstats.slq = slq;
  15783.         su_ds.globals.sluqh[url] = slq;
  15784.         var slistats = su_ds.getValue("$slistats").split(":");
  15785.         for (i = 0; i < urls.length; i++)
  15786.         {
  15787.             var slt = "" + slq + su_service.getSha1(hrefs[i]);
  15788.             var sli = new Object();
  15789.             sli.i = i;
  15790.             su_ds.globals.sltih[slt] = sli;
  15791.             if (i < 10)
  15792.                 slistats[i] = parseInt(slistats[i]) + 1;
  15793.         }
  15794.         su_ds.setValue("$slistats", slistats.join(":"));
  15795.     }
  15796.     
  15797.     
  15798.     var context = new Object();
  15799.     context.slstats = slstats;
  15800.     context.done = false;
  15801.     context.batch_count = 0;
  15802.     context.url_start_index = 0;
  15803.     context.doc = doc;
  15804.     context.timestamp = now;
  15805.     context.query_detail = query_detail;
  15806.     context.before_targets = before_targets;
  15807.     context.after_targets = after_targets;
  15808.     context.urls = urls;
  15809.     context.hrefs = hrefs;
  15810.     context.linked_color = linked_color;
  15811.     context.underline = underline;
  15812.     context.unlinked_color = unlinked_color;
  15813.     context.font_size = font_size;
  15814.     context.force_logo = force_logo;
  15815.     context.soft_wrap = soft_wrap;
  15816.     context.hard_wrap = hard_wrap;
  15817.     context.include_topic = include_topic || su_ds.getValue("$show_searchlinks_topic");
  15818.     context.image_baseline = image_baseline;
  15819.     context.enable_click_tracking = enable_click_tracking;
  15820.     context.force_inline = force_inline;
  15821.     
  15822.     su_augment_links2(context);
  15823. }
  15824.  
  15825. function su_augment_links2(context)
  15826. {
  15827.     var query = "";
  15828.     if (0) //(su_ds.hasFeature("$unbatchedlinks"))
  15829.     {
  15830.         context.done = true;
  15831.         for (i = 0; i < context.urls.length; i++)
  15832.         {
  15833.             if (query != "")
  15834.                 query += '%09';
  15835.             query += encodeURIComponent(context.urls[i]);
  15836.         }
  15837.     }
  15838.     else
  15839.     {
  15840.         var url_count = 0;
  15841.         var i = (context.batch_count * 10);
  15842.         context.url_start_index = i;
  15843.         while ((url_count < 10) && (i < context.urls.length))
  15844.         {
  15845.             url_count++;
  15846.             if (query != "")
  15847.                 query += '%09';
  15848.             query += encodeURIComponent(context.urls[i]);
  15849.             i++;
  15850.         }
  15851.         context.batch_count++;
  15852.         if (su_ds.hasFeature("$limitedlinks"))
  15853.             context.done = true;
  15854.         else
  15855.             context.done = (i == context.urls.length);
  15856.     }
  15857.     
  15858.     if (query == "")
  15859.         return;
  15860.     
  15861.     var params = "u=" + query;
  15862.     params = su_arp(params, "f",
  15863.                 su_ds.getValue("$show_searchlinks_friends") ? 1 : 0);
  15864.     params = su_arp(params, "s",
  15865.                 su_ds.getValue("$show_searchlinks_score") ? 1 : 0);
  15866.     params = su_arp(params, "t",
  15867.                 su_ds.getValue("$show_searchlinks_topic") ? 1 : 0);
  15868.     params = su_arp(params, "m", su_ds.getValue("@dd_links_m"));
  15869.     params = su_arp(params, "domain", context.query_detail.domain);
  15870.     params = su_arp(params, "termcount", context.query_detail.term_count);
  15871.     params = su_arp(params, "firstpage", context.query_detail.is_first_page ? 1 : 0);
  15872.     params = su_arp(params, "timestamp", context.timestamp);
  15873.     params = su_arp(params, "batch", context.batch_count);
  15874.     
  15875.     var loc = "links.php";
  15876.     if (su_ds.getValue("@dd_links_m") == "alt")
  15877.         loc = "test_links.php";
  15878.     
  15879.     su_post_url_server_async(
  15880.                 loc, 
  15881.                 params,
  15882.                 60000,
  15883.                 su_augment_links_done,
  15884.                 context);
  15885. }
  15886.  
  15887. // handles response to links.php; adds content for the links
  15888. function su_augment_links_done(res)
  15889. {
  15890.     try {
  15891.         if ((res.status != 200) || res.aborted)
  15892.             return;
  15893.     } catch (e) { return; }
  15894.  
  15895.     var context = res.detail;
  15896.  
  15897.     var s = "";
  15898.     if (typeof(res.responseText) != "undefined")
  15899.         s = res.responseText;
  15900.  
  15901.     if (su_log_communication)
  15902.         su_log("response links.php", s);
  15903.  
  15904.     if (s == "")
  15905.         return;
  15906.     
  15907.     var ss;
  15908.  
  15909.     ss = s.split("\n");
  15910.  
  15911.     var sss = ss[0].split(" ");
  15912.  
  15913.     if (sss[0] == "ERROR")
  15914.         return;
  15915.  
  15916.     var i;
  15917.     var slt;
  15918.     var slistats = su_ds.getValue("$slistats").split(":");
  15919.     var slidfstats = su_ds.getValue("$slidfstats").split(":");
  15920.     for (i = 0; i < ss.length; i++)
  15921.     {
  15922.         if (ss[i] == "")
  15923.             continue;
  15924.         
  15925.         var url_index = context.url_start_index + i;
  15926.         
  15927.         context.slstats.decorated_count++;
  15928.         if (! context.slstats.first_decorated_num)
  15929.             context.slstats.first_decorated_num = (i + 1);
  15930.         
  15931.         var fields = ss[i].split("\t");
  15932.         var comment_level = parseInt(fields[0]);
  15933.         var thumbed = fields[1];
  15934.         if (su_ratings[context.hrefs[url_index]])
  15935.             thumbed = "1";
  15936.         var score = parseInt(fields[2]);
  15937.         var topic = fields[3];
  15938.  
  15939.         var friends = new Array();
  15940.         var j;
  15941.         if (typeof(fields[4]) != "undefined" && fields[4] != "" && su_ds.getValue("$show_searchlinks_friends"))
  15942.         {
  15943.             var f = fields[4].split(",");
  15944.             for (j = 0; j < f.length; j++)
  15945.             {
  15946.                 if (f[j] == '')
  15947.                     continue;
  15948.                 friends.push(f[j]);
  15949.             }
  15950.         }
  15951.         
  15952.         var comment_count = null;
  15953.         if (typeof(fields[5]) != "undefined" && fields[5] != "")
  15954.             comment_count = parseInt(fields[5]);
  15955.         
  15956.         var comment_id = null;
  15957.         if (typeof(fields[6]) != "undefined" && fields[6] != "")
  15958.             comment_id = fields[6];
  15959.         
  15960.         var comment_text = null;
  15961.         if (typeof(fields[7]) != "undefined" && fields[7] != "")
  15962.             comment_text = fields[7].replace(/\|/g, " ");
  15963.         
  15964.         slt = "";
  15965.         if (su_host.sha1 && su_ds.getValue("@enable_slstats") && context.enable_click_tracking)
  15966.         {
  15967.             slt = "" + context.slstats.slq + su_service.getSha1(context.hrefs[url_index]);
  15968.             var sli = su_ds.globals.sltih[slt];
  15969.             var detail = new Object();
  15970.             sli.detail = detail;
  15971.             detail.q = context.slstats.slq;
  15972.             detail.d = 1;
  15973.             detail.i = url_index;
  15974.             detail.dt = (thumbed) ? 1 : 0;
  15975.             detail.dc = (comment_count) ? comment_count : 0;
  15976.             detail.ds = score;
  15977.             detail.dl = comment_level;
  15978.             detail.df = friends.length;
  15979.             detail.dr = (comment_text) ? 1 : 0;
  15980.             detail.dz = (context.include_topic && (typeof(su_catnames[topic]) != "undefined")) ? 1 : 0;
  15981.             
  15982.             if (url_index < 10 && detail.df)
  15983.             {
  15984.                 slistats[url_index] = parseInt(slistats[url_index]) - 1;
  15985.                 slidfstats[url_index] = parseInt(slidfstats[url_index]) + 1;
  15986.             }
  15987.         }
  15988.         
  15989.         if (! score)
  15990.             score = 1;
  15991.         
  15992.         var after;
  15993.         var before;
  15994.         var after_parts =  new Array();
  15995.         var reviewHref = su_base_url + "url/" + su_review_url(context.urls[url_index]);
  15996.  
  15997.         
  15998.         // The 'float:none;padding:0;' and 'display:inline;' css rules in
  15999.         // here mostly cater to AOL.
  16000.         
  16001.         before = "";
  16002.         if (thumbed == "1")
  16003.         {
  16004.             before = '<img border="0" width="13" height="13" style="display:inline;';
  16005.             if (context.image_baseline)
  16006.                 before += 'vertical-align:baseline;';
  16007.             before += '" src="chrome://stumbleupon/content/skin/smallgreenthumbup.png"> ';
  16008.         }
  16009.         
  16010.         after = '';
  16011.         if (context.hard_wrap)
  16012.         {
  16013.             after_parts.push("<br />");
  16014.         }
  16015.         else if ((score <= 0) && (! su_ds.getValue("$show_searchlinks_logo")))
  16016.         {
  16017.             after += '<span style="font-size:' + context.font_size + 
  16018.                 ';color:' + context.unlinked_color +
  16019.                 ';float:none;padding:0;"> ·</span>';
  16020.         }
  16021.         else
  16022.         {
  16023.             after += ' ';
  16024.         }
  16025.  
  16026.         after += '<a ondblclick="slu" slt="' + slt + '"';
  16027.  
  16028.         if ((! context.include_topic) && (typeof(su_catnames[topic]) != "undefined"))
  16029.         {
  16030.             after += ' title="';
  16031.             if (comment_count)
  16032.             {
  16033.                 if (comment_count == 1)
  16034.                     after += 'Read 1 review';
  16035.                 else
  16036.                     after += 'Read ' + comment_count + ' reviews';
  16037.                 after += ' in topic ' + su_catnames[topic] + '"';
  16038.             }
  16039.             else
  16040.             {
  16041.                 after += 'See who liked this"';
  16042.             }
  16043.         }
  16044.         else if (comment_count)
  16045.         {
  16046.             after += ' title="';
  16047.             if (comment_count == 1)
  16048.                 after += 'Read 1 review"';
  16049.             else
  16050.                 after += 'Read ' + comment_count + ' reviews"';
  16051.         }
  16052.         else
  16053.         {
  16054.             after += ' title="See who liked this"';
  16055.         }
  16056.  
  16057.         after += ' style="text-decoration:none;float:none;padding:0;font-size:' + 
  16058.                     context.font_size + ';color:' + 
  16059.                     context.linked_color + ';" href="' + reviewHref + '">';
  16060.  
  16061.         var imgStyle = "display:inline;float:none;border:none;margin:0px;padding:0px;";
  16062.         if (context.force_logo || su_ds.getValue("$show_searchlinks_logo"))
  16063.         {
  16064.             after += '<img ondblclick="slu" border="0" width="13" height="13" style="' + imgStyle;
  16065.             if (context.image_baseline)
  16066.                 after += 'vertical-align:baseline;';
  16067.             after += '" src="chrome://stumbleupon/content/skin/smallstumble.png">';
  16068.         }
  16069.         
  16070.         if ((score > 0) && su_ds.getValue("$show_searchlinks_score"))
  16071.         {
  16072.             after += ' ';
  16073.         
  16074.             for (j = 0; j < score; j++)
  16075.             {
  16076.                 after += '<img ondblclick="slu" border="0" width="10" height="10" style="' + imgStyle;
  16077.                 if (context.image_baseline)
  16078.                     after += 'vertical-align:baseline;';
  16079.                 after += '" src="chrome://stumbleupon/content/skin/star.png">';
  16080.             }
  16081.         }
  16082. //        else if ((friends.length == 0) || 
  16083. //                    (! su_ds.getValue("$show_searchlinks_friends")))
  16084. //        {
  16085. //            if (context.underline)
  16086. //                after += ' <u ondblclick="slu">Reviews</u>';
  16087. //            else
  16088. //                after += ' Reviews';
  16089. //        }
  16090.  
  16091.         if ((comment_level > 0) && su_ds.getValue("$show_searchlinks_comment_icon"))
  16092.         {
  16093.             after += ' <img ondblclick="slu" border="0" width="13" height="13" style="' + imgStyle;
  16094.             if (context.image_baseline)
  16095.                 after+= 'vertical-align:baseline;';
  16096.             after += '" src="chrome://stumbleupon/content/skin/smallbubble' + comment_level + '.png">';
  16097.         }
  16098.  
  16099.         after += '</a>';            
  16100.         after_parts.push(after);
  16101.         
  16102.         after = '';
  16103.         if (friends.length && su_ds.getValue("$show_searchlinks_friends"))
  16104.         {
  16105.             for (j = 0; j < friends.length; j++)
  16106.             {
  16107.                 if (j == 0)
  16108.                 {
  16109.                     after = '<span style="text-decoration:none;float:none;padding:0;font-size:' + 
  16110.                                 context.font_size + ';color:' + 
  16111.                                 context.unlinked_color + ';"> · </span><a ondblclick="slp" slt="' +
  16112.                                 slt + '" style="text-decoration:none;float:none;padding:0;font-size:' + 
  16113.                                 context.font_size + ';color:' + 
  16114.                                 context.linked_color + ';" title="'; 
  16115.                     
  16116.                     if (comment_text)
  16117.                         after += comment_text;
  16118.                     else
  16119.                         after += friends[j] + ' likes this page';
  16120.                     
  16121.                     after += '" href="' + reviewHref + '">';
  16122.                     
  16123.                     after += '<img ondblclick="slp" border="0" width="13" height="13" style="' + imgStyle;
  16124.                     if (context.image_baseline)
  16125.                         after += 'vertical-align:baseline;';
  16126.                     
  16127.                     after += '" src="chrome://stumbleupon/content/skin/smallredman.png"> ';
  16128.                     
  16129.                     if (context.underline)
  16130.                         after += '<u ondblclick="slp">' + friends[j] + '</u>';
  16131.                     else
  16132.                         after += friends[j];
  16133.                     
  16134.                     after += '</a>';
  16135.                     
  16136. //                    after_parts.push(after);
  16137.                     
  16138.                 }
  16139.                 else if (j == 1)
  16140.                 {
  16141.                     after += '<span style="text-decoration:none;float:none;padding:0;font-size:' + 
  16142.                                 context.font_size + ';color:' + 
  16143.                                 context.unlinked_color + ';"> + </span>';
  16144.                     
  16145.                     after += '<a ondblclick="sln" slt="' + slt + 
  16146.                                 '" style="text-decoration:none;float:none;padding:0;font-size:' + 
  16147.                                 context.font_size + ';color:' + 
  16148.                                 context.linked_color + ';" href="' + reviewHref + '" title="' + 
  16149.                                 friends[0] + ', ' + friends[1];
  16150.                 }
  16151.                 else
  16152.                 {
  16153.                     after += ', ' + friends[j];
  16154.                 }
  16155.             }
  16156.             
  16157.             if (friends.length > 1)
  16158.             {
  16159.                 after += ' like';
  16160.             
  16161.                 if (friends.length == 1)
  16162.                     after += 's';
  16163.                 
  16164.                 after += ' this page">' + (friends.length - 1) + '</a>';
  16165.             }
  16166.         }
  16167.         
  16168.         if (context.include_topic && (typeof(su_catnames[topic]) != "undefined"))
  16169.         {
  16170.             after += '<span style="text-decoration:none;float:none;padding:0;font-size:' + 
  16171.                         context.font_size + ';color:' + 
  16172.                         context.unlinked_color + ';"> · </span><a ondblclick="slz" slt="' + slt + 
  16173.                         '" title="See related pages" style="text-decoration:none;float:none;padding:0;font-size:' + 
  16174.                         context.font_size + ';color:' + 
  16175.                         context.linked_color + ';"href="' + su_serverhttp + 
  16176.                         'tag/' + su_catnames[topic].toLowerCase() + '/">';
  16177.             if (context.underline)
  16178.                 after += '<u ondblclick="slz">' + su_catnames[topic] + '</u>';
  16179.             else
  16180.                 after += su_catnames[topic];
  16181.             after += '</a>';
  16182.         }
  16183.         
  16184.         if (after != '')
  16185.             after_parts.push(after);
  16186.     
  16187.         var el;
  16188.         if (before != "")
  16189.         {
  16190.             el = context.doc.createElement("SPAN");
  16191.             el.style.cssText = "white-space:nowrap!important; float:none!important; padding:0!important; text-decoration:none!important;";
  16192.             el.innerHTML = before;
  16193.             context.before_targets[url_index].parentNode.insertBefore(el, context.before_targets[url_index]);
  16194.         }
  16195.         
  16196.         var after_target = context.after_targets[url_index];
  16197.         
  16198.         if (! context.soft_wrap)
  16199.             after_parts = new Array(after_parts.join(""));
  16200.         
  16201.         for (j = 0; j < after_parts.length; j++)
  16202.         {
  16203.             el = context.doc.createElement("SPAN");
  16204.             var cssText = "white-space:nowrap!important; float:none!important; padding:0!important; text-decoration:none!important;";
  16205.             if(context.force_inline)
  16206.             {
  16207.                 cssText += "display:inline!important;";
  16208.             }
  16209.             if (context.soft_wrap)
  16210.                 el.innerHTML = after_parts[j].replace(/ /g, " ");
  16211.             else
  16212.                 el.innerHTML = after_parts[j];
  16213.             if (after_target.nextSibling)
  16214.                 after_target.parentNode.insertBefore(el, after_target.nextSibling);
  16215.             else
  16216.                 after_target.parentNode.appendChild(el);
  16217.             after_target = el;
  16218.             el.style.cssText = cssText;
  16219.         }
  16220.     }
  16221.     
  16222.     if (context.enable_click_tracking)
  16223.     {
  16224.         var str = "";
  16225.         var sls = su_ds.globals.sls;
  16226.         for (i = 0; i < sls.length; i++)
  16227.         {
  16228.             var slstats = sls[i]
  16229.             str += slstats.timestamp + "\t" + slstats.slq + "\t" + 
  16230.                     slstats.term_count + "\t" + slstats.url_count + "\t" +
  16231.                     slstats.decorated_count + "\t" + 
  16232.                     slstats.first_decorated_num + "\t:";
  16233.         }
  16234.         
  16235.         su_ds.setValue("$slstats", str);
  16236.         su_ds.setValue("$slistats", slistats.join(":"));
  16237.         su_ds.setValue("$slidfstats", slidfstats.join(":"));
  16238.     }
  16239.     
  16240.     if (! context.done)
  16241.         su_augment_links2(context);
  16242. }
  16243.  
  16244. function su_handle_upgrade_click(event)
  16245. {
  16246.     var target = "https://addons.mozilla.org/firefox/138/";
  16247.     su_set_location(target, null, su_new_tab(event));
  16248.     su_set_visible("su_upgrade", false);
  16249. }
  16250.  
  16251. function su_handle_stumble_topic_click(event, url)
  16252. {
  16253.     su_set_server_location(
  16254.                 "url/" + su_review_url(url),
  16255.                 null,
  16256.                 su_new_tab(event));
  16257. }
  16258.  
  16259. // Generates the topic menu
  16260. function su_prepare_stumble_topic_menu(event, url)
  16261. {
  16262.     var menuEl;
  16263.     if (su_ds.getValue("$stumble_topics_style") == 1)
  16264.         menuEl = su_get_element("su_stumble_topic_menu_right_popup")
  16265.     else
  16266.         menuEl = su_get_element("su_stumble_topic_menu_left_popup");
  16267.     
  16268.     if (event.originalTarget != menuEl)
  16269.         return;
  16270.     
  16271.     if (menuEl.getAttribute("data-url") == url)
  16272.         return;
  16273.     
  16274.     menuEl.removeAttribute("data-url");
  16275.     menuEl.setAttribute("data-url", url);
  16276.  
  16277.     // Check if a menu already exists -> If so, we need to remove it
  16278.     while(menuEl.childNodes.length)
  16279.         menuEl.removeChild(menuEl.firstChild);
  16280.     
  16281.     var url_detail = su_ds.lookup("url:url_detail", url);
  16282.     var item;
  16283.     var submenu;
  16284.  
  16285.     item = document.createElement("menu");
  16286.     item.setAttribute("label", " Report a problem");
  16287.     item.setAttribute("tooltiptext", "Report...");
  16288.     menuEl.appendChild(item);
  16289.     submenu = document.createElement("menupopup");
  16290.     submenu.setAttribute("id", "su_report_popup");
  16291.     item.appendChild(submenu);
  16292.     
  16293.     su_prepare_reporting_menu(submenu, url_detail, false, url_detail.url);
  16294.     
  16295.     item = document.createElement("menuseparator");
  16296.     menuEl.appendChild(item);
  16297.     
  16298.     item = document.createElement("menuitem");
  16299.     item.setAttribute("label", "This page is about:");
  16300.     item.setAttribute("tooltiptext", "Change topic to...");
  16301.     item.setAttribute("style", "font-weight: bold; color: #404040;");
  16302.     item.setAttribute("disabled", "true");
  16303.     menuEl.appendChild(item);
  16304.     
  16305.     var stumbler_name = su_get_profile_nickname(url);
  16306.     
  16307.     if (stumbler_name)
  16308.     {
  16309.         item = document.createElement("menuitem")
  16310.         item.setAttribute("label", "Stumbler"); // note: actual name is 'Stumblers'
  16311.         if (url_detail.cur_catid == 44)
  16312.         {
  16313.             item.setAttribute("type", "checkbox");
  16314.             item.setAttribute("checked", "true");
  16315.             item.setAttribute("tooltiptext", "This is a stumbler profile");
  16316.             item.setAttribute("oncommand", 'su_handle_recat_reset_checkbox();');
  16317.             item.style.fontWeight = 'bold';
  16318.             item.style.color = "#008B00";
  16319.         }
  16320.         else
  16321.         {
  16322.             item.setAttribute("tooltiptext", "Request topic change from " + url_detail.cur_topic_name + " to Stumblers");
  16323.             item.setAttribute("oncommand",
  16324.                     'su_handle_recat_page(event, "' + url + '", 44, "Stumbler");');
  16325.         }
  16326.         menuEl.appendChild(item);
  16327.         
  16328.         item = document.createElement("menuitem")
  16329.         item.setAttribute("label", "Adult Stumbler");
  16330.         if (url_detail.cur_catid == 520)
  16331.         {
  16332.             item.setAttribute("type", "checkbox");
  16333.             item.setAttribute("checked", "true");
  16334.             item.setAttribute("tooltiptext", "This is an adult stumbler profile");
  16335.             item.setAttribute("oncommand", 'su_handle_recat_reset_checkbox();');
  16336.             item.style.fontWeight = 'bold';
  16337.             item.style.color = "#008B00";
  16338.         }
  16339.         else
  16340.         {
  16341.             item.setAttribute("tooltiptext", "Request topic change from " + url_detail.cur_topic_name + " to Adult Stumbler");
  16342.             item.setAttribute("oncommand",
  16343.                     'su_handle_recat_page(event, "' + url + '", 520, "Adult Stumbler");');
  16344.         }
  16345.         menuEl.appendChild(item);
  16346.         
  16347.         return;
  16348.     }
  16349.  
  16350.     var recat_adult = su_ds.getValue("$recat_adult");
  16351.     
  16352.     // Add list of topics
  16353.     var folders = new Array();
  16354.     var folders_sorted = new Array();
  16355.     var cats_sorted = new Array();
  16356.     for (var cat in su_catnames)
  16357.     {
  16358.         if (typeof(su_topicfolders[cat]) == "undefined")
  16359.             continue;
  16360.         var folder = su_topicfolders[cat];
  16361.         var name = su_catnames[cat];
  16362.         if (typeof(folders[folder]) == "undefined")
  16363.         {
  16364.             folders[folder] = new Array();
  16365.             folders_sorted.push(folder);
  16366.             cats_sorted[folder] = new Array();
  16367.         }
  16368.     
  16369.         folders[folder][name]=cat;
  16370.         cats_sorted[folder].push(name);
  16371.     }
  16372.     
  16373.     folders_sorted.sort();
  16374.     
  16375.     var nickname = su_get_profile_nickname(url);
  16376.     
  16377.     for (var i = 0 ; i < folders_sorted.length ; i++)
  16378.     {
  16379.         var folder = folders_sorted[i];
  16380.         
  16381.         if (folder == "0")
  16382.             continue; // Special treatment for the "StumbleUpon news" cat
  16383.         
  16384.         var item = document.createElement("menu");
  16385.         item.setAttribute("label", folder);
  16386.         item.setAttribute("tooltiptext", "Change topic to...");
  16387.         //item.setAttribute("oncommand",
  16388.         //        'su_handle_stumble_topic_click(event, "' + url + '");');
  16389.         menuEl.appendChild(item);
  16390.         var foldermenu = document.createElement("menupopup");
  16391.         item.appendChild(foldermenu);
  16392.         
  16393.         cats_sorted[folder].sort();
  16394.         for ( var j = 0 ; j < cats_sorted[folder].length ; j++)
  16395.         {
  16396.             var cat = cats_sorted[folder][j];
  16397.             var jcatid = folders[folder][cat];
  16398.             if (folder == "Adult")
  16399.             {
  16400.                 if (recat_adult == 0 && nickname && jcatid != 520)
  16401.                     continue;
  16402.                 else if (recat_adult == 0 && jcatid != 6 && jcatid != 500)
  16403.                     continue;
  16404.                 else if (recat_adult == 1 && jcatid != 6 && su_ds.lookup("catid:x_flag", jcatid))
  16405.                     continue;
  16406.             }
  16407.             
  16408.             var itemCat = document.createElement("menuitem")
  16409.             itemCat.setAttribute("label", cat);
  16410.             if (jcatid == url_detail.cur_catid)
  16411.             {
  16412.                 itemCat.setAttribute("type", "checkbox");
  16413.                 itemCat.setAttribute("checked", "true");
  16414.                 itemCat.setAttribute("tooltiptext", "This page is about " + url_detail.cur_topic_name);
  16415.                 itemCat.setAttribute("oncommand", 'su_handle_recat_reset_checkbox();');
  16416.                 item.style.fontWeight = 'bold';
  16417.                 item.style.color = "#008B00";
  16418.             }
  16419.             else
  16420.             {
  16421.                 itemCat.setAttribute("tooltiptext", "Request topic change from " + url_detail.cur_topic_name + " to " + cat);
  16422.                 itemCat.setAttribute("oncommand",
  16423.                         'su_handle_recat_page(event, "' + url + '", "' + jcatid + '", "' + cat + '");');
  16424.             }
  16425.             foldermenu.appendChild(itemCat);
  16426.             
  16427.             if (jcatid == url_detail.cur_catid)
  16428.             {
  16429.                 itemCat.style.fontWeight = 'bold';
  16430.                 itemCat.style.color = "#008B00";
  16431.             }
  16432.         }
  16433.     }
  16434.     
  16435.     var catid2 = url_detail.catid2;
  16436.     var catid3 = url_detail.catid3;
  16437.     var has_cat2 = (catid2 && catid2 != url_detail.cur_catid && su_catnames[catid2] && su_catnames[catid2] != '');
  16438.     var has_cat3 = (catid3 && catid3 != url_detail.cur_catid && catid3 != catid2 && su_catnames[catid3] && su_catnames[catid3] != '');
  16439.     
  16440.     if (has_cat2 || has_cat3)
  16441.     {
  16442.         item = document.createElement("menuitem");
  16443.         item.setAttribute("label", "Suggested:");
  16444.         item.setAttribute("tooltiptext", "Change topic to...");
  16445. //        if (has_cat2 && has_cat3)
  16446. //            item.setAttribute("label", "Suggested alternates:");
  16447. //        else
  16448. //            item.setAttribute("label", "Suggested alternate:");
  16449.         item.setAttribute("disabled", "true");
  16450.         item.setAttribute("style", "font-weight: bold; color: #707070;");
  16451.         menuEl.appendChild(item);
  16452.     }
  16453.     
  16454.     // Add possible choices
  16455.     if (has_cat2)
  16456.     {
  16457.         var itemCat = document.createElement("menuitem")
  16458.         itemCat.setAttribute("label", " " + su_catnames[catid2]);
  16459.         itemCat.setAttribute("tooltiptext", "Request topic change from " + url_detail.cur_topic_name + " to " + su_catnames[catid2]);
  16460.         itemCat.setAttribute("oncommand",
  16461.             'su_handle_recat_page(event, "' + url + '", "' + catid2 + '", "' + su_catnames[catid2] + '");');
  16462.         menuEl.appendChild(itemCat);
  16463.     }
  16464.     
  16465.     if (has_cat3)
  16466.     {
  16467.         var itemCat = document.createElement("menuitem")
  16468.         itemCat.setAttribute("label", " " + su_catnames[catid3]);
  16469.         itemCat.setAttribute("tooltiptext", "Request topic change from " + url_detail.cur_topic_name + " to " + su_catnames[catid3]);
  16470.         itemCat.setAttribute("oncommand",
  16471.             'su_handle_recat_page(event, "' + url + '", "' + catid3 + '", "' + su_catnames[catid3] + '");');
  16472.         menuEl.appendChild(itemCat);
  16473.     }
  16474.  
  16475. }
  16476.  
  16477. function su_handle_recat_reset_checkbox()
  16478. {
  16479.     su_check_progress_listener();
  16480.     
  16481.     var menuEl;
  16482.     if (su_ds.getValue("$stumble_topics_style") == 1)
  16483.         menuEl = su_get_element("su_stumble_topic_menu_right_popup")
  16484.     else
  16485.         menuEl = su_get_element("su_stumble_topic_menu_left_popup");
  16486.     
  16487.     // Menu will be recreated
  16488.     menuEl.removeAttribute("data-url");
  16489. }
  16490.  
  16491. // Handle recat of a stumble page using the topic menu
  16492. function su_handle_recat_page(event, url, catid, topic_name)
  16493. {
  16494.     su_check_progress_listener();
  16495.     
  16496.     var detail = new Object();
  16497.     detail.url = url;
  16498.     detail.new_catid = catid;
  16499.     detail.new_topic_name = topic_name;
  16500.  
  16501.     var url_detail = su_ds.lookup("url:url_detail", url);
  16502.     if (url_detail)
  16503.     {
  16504.         detail.old_catid = url_detail.cur_catid;
  16505.         detail.old_topic_name = url_detail.cur_topic_name;
  16506.     }
  16507.     else
  16508.     {
  16509.         detail.old_catid = 0;
  16510.         detail.old_topic_name = "unknown";
  16511.     }
  16512.     
  16513.     window.openDialog(
  16514.                 "chrome://stumbleupon/content/reportTopicDialog.xul",
  16515.                 "",
  16516.                 "chrome,titlebar,close,dialog,centerscreen,dependent",
  16517.                 detail);
  16518. }
  16519.  
  16520. function su_handle_report_topic_dialog_accept(detail)
  16521. {
  16522.     var url_detail = su_ds.lookup("url:url_detail", detail.url);
  16523.     url_detail.cur_catid = detail.new_catid;
  16524.     url_detail.cur_topic_name = detail.new_topic_name;
  16525.     su_change_local_catid(detail.url, detail.new_catid);
  16526.     
  16527.     var menuEl;
  16528.     if (su_ds.getValue("$stumble_topics_style") == 1)
  16529.         menuEl = su_get_element("su_stumble_topic_menu_right_popup")
  16530.     else
  16531.         menuEl = su_get_element("su_stumble_topic_menu_left_popup");
  16532.     
  16533.     // Menu will be recreated
  16534.     menuEl.removeAttribute("data-url");
  16535.     menuEl.setAttribute("onpopupshowing",
  16536.             'su_prepare_stumble_topic_menu(event, "' + detail.url + '");');
  16537.     menuEl.parentNode.setAttribute("label", detail.new_topic_name);
  16538.     
  16539.     // Tell the server to recat the page
  16540.     var doc = getBrowser().contentDocument;
  16541.     var context = new su_AsyncContext();
  16542.     context.url = detail.url;
  16543.     context.ref_url = su_get_browser_url(doc, true);
  16544.     context.title = su_get_title(doc, context.ref_url);
  16545.     
  16546.     var params = "";
  16547.     params = su_arp(params, "url", detail.url);
  16548.     params = su_arp(params, "redirect", url_detail.redirect_url);
  16549.     params = su_arp(params, "current", su_get_browser_url());
  16550.     params = su_arp(params, "newcatid", detail.new_catid);
  16551.     
  16552.     params = su_append_sync_params(params);
  16553.     
  16554.     su_post_url_server_async(
  16555.                 "recat.php",
  16556.                 params,
  16557.                 null,
  16558.                 su_generic_done,
  16559.                 context);
  16560.  
  16561.     su_check_progress_listener();
  16562. }
  16563.  
  16564. function su_handle_sponsor_click(event)
  16565. {
  16566.     var target = "sponsored_page.html";
  16567.     su_set_server_location(target, null, su_new_tab(event));
  16568. }
  16569.  
  16570. function su_handle_bug_command()
  16571. {
  16572.     var email = "joe@stumbleupon.com";
  16573.     var date = new Date();
  16574.     var str;
  16575.     
  16576.     str = "";
  16577.     str += "The toolbar will now open two tabs:\n\n";
  16578.     str += "o The first tab will attempt to open your e-mail application.\n\n";
  16579.     str += "o The second tab will display the error report.  Use this if you\n";
  16580.     str += "   prefer to copy-and-paste into a web-based e-mail account.\n";
  16581.     str += " ";
  16582.     var response = confirm(str);
  16583.     
  16584.     if (! response)
  16585.         return;
  16586.     
  16587.     str = "[";
  16588.     if ((stumbleid != 0) && su_ds && (su_ds.getValue("$nick") != "")) 
  16589.         str += su_ds.getValue("$nick") + ":";
  16590.     if (stumbleid != 0)
  16591.         str += stumbleid + "] ";
  16592.     str += "toolbar bug report";
  16593.     var subject = str;
  16594.     
  16595.     
  16596.     str = "=== behavior ===\n";
  16597.     str += "\n";
  16598.     str += "Please describe the action(s) you performed.\n";
  16599.     str += "\n";
  16600.     str += "Then describe how the toolbar responded.\n";
  16601.     str += "\n";
  16602.     str += "Feel free to attach screenshots if applicable.\n";
  16603.     str += "\n";
  16604.     str += "\n";
  16605.     str += "=== platform ===\n";
  16606.     str += su_host.desc + "\n";
  16607.     str += navigator.userAgent + "\n";
  16608.     str += su_useragent + "\n";
  16609.     str += date.toUTCString() + "\n";
  16610.     if (su_service && (su_service._messageLog != ""))
  16611.     {
  16612.         str += "\n";
  16613.         str += "\n";
  16614.         str += "=== log ===";
  16615.         str += su_service._messageLog;
  16616.     }
  16617.     try {
  16618.         str += "\n\n" + su_get_addons_desc();
  16619.     } catch (e) {}
  16620.     var body = str;
  16621.     
  16622.     
  16623.     str = "mailto:" + email + "?subject=";
  16624.     str += encodeURIComponent(subject) + "&body=";
  16625.     str += encodeURIComponent(body);
  16626.     
  16627.     su_set_location(str, null, true);
  16628.     
  16629.     str = "\n     TO: " + email + "\n";
  16630.     str += "SUBJECT: " + subject + "\n\n\n" 
  16631.     str += body;
  16632.     
  16633.     var filename = date.getTime() + ".txt"; 
  16634.     su_ds.writeFile(
  16635.                 su_ds.getResourceNSIFile("reports", filename), 
  16636.                 str);
  16637.     
  16638.     su_set_location(
  16639.                 su_ds.getResourceURLFromName("reports", filename),
  16640.                 null,
  16641.                 true);
  16642. }
  16643.  
  16644. function su_get_addons_desc()
  16645. {
  16646.     var i;
  16647.     var datasource = su_get_service(
  16648.                 "@mozilla.org/extensions/manager;1",
  16649.                 "nsIExtensionManager")
  16650.                 .datasource;
  16651.     var root = su_get_rdf_resource("urn:mozilla:item:root");
  16652.     var container = su_create_instance(
  16653.                 "@mozilla.org/rdf/container;1",
  16654.                 "nsIRDFContainer");
  16655.     container.Init(datasource, root);
  16656.     var elements = container.GetElements();
  16657.  
  16658.     var attributes = new Array(
  16659.                 "name",
  16660.                 "version",
  16661.                 "appDisabled",
  16662.                 "userDisabled",
  16663.                 "internalName");
  16664.                 
  16665.     var extensions = new Array();
  16666.     var themes = new Array();
  16667.  
  16668.     while(elements.hasMoreElements())
  16669.     {
  16670.         var element = elements.getNext();
  16671.         var item = new Object();
  16672.         for (i = 0; i < attributes.length; i++)
  16673.         {
  16674.             item[attributes[i]] = su_get_rdf_arc_literal(
  16675.                         datasource,
  16676.                         element,
  16677.                         "http://www.mozilla.org/2004/em-rdf#" + attributes[i]);
  16678.         }
  16679.  
  16680.         var type_id = su_get_rdf_arc_int(
  16681.                     datasource,
  16682.                     element,
  16683.                     "http://www.mozilla.org/2004/em-rdf#type");
  16684.                     
  16685.         switch (type_id)
  16686.         {
  16687.             case 2: extensions.push(item); break;
  16688.             case 4: themes.push(item); break;
  16689.         }
  16690.     }
  16691.     
  16692.     extensions.sort(function (a, b)
  16693.                 { 
  16694.                     return a.name.toLowerCase() > b.name.toLowerCase();
  16695.                 });
  16696.  
  16697.     themes.sort(function (a, b)
  16698.                 {
  16699.                     return a.name.toLowerCase() > b.name.toLowerCase();
  16700.                 });
  16701.     
  16702.     var str = "=== extensions ===\n";
  16703.     for (i = 0; i < extensions.length; i++)
  16704.     {
  16705.         str += extensions[i].name + " ";
  16706.         str += extensions[i].version;
  16707.         if (extensions[i].appDisabled || extensions[i].userDisabled)
  16708.             str += " [disabled]";
  16709.         str += "\n";
  16710.     }
  16711.     
  16712.     var current_theme = null;
  16713.     try {
  16714.         current_theme = su_ds.getValue("general.skins.selectedSkin");
  16715.     } catch(e) {}
  16716.  
  16717.     str += "\n\n=== themes ===\n";
  16718.     for (i = 0; i < themes.length; i++)
  16719.     {
  16720.         str += themes[i].name + " ";
  16721.         str += themes[i].version;
  16722.         if (themes[i].internalName == current_theme)
  16723.             str += " [selected]";
  16724.         str += "\n";
  16725.     }
  16726.     return str;
  16727. }
  16728.  
  16729.  
  16730. function su_refresh_pagemeta(from_stumblevideo_page, from)
  16731. {
  16732.     if (su_refreshing_pagemeta)
  16733.         return;
  16734.     
  16735.     su_refreshing_pagemeta = true;
  16736.     
  16737.     setTimeout(
  16738.                 su_update_pagemeta,
  16739.                 100,
  16740.                 from_stumblevideo_page,
  16741.                 from);
  16742. }
  16743.  
  16744.  
  16745. // Handler for when the page being viewed changes.
  16746. function su_update_pagemeta(from_stumblevideo_page, from)
  16747. {
  16748.     //!!! This needs either (a) to get some code documentation or (b)
  16749.     //    to be refactored into several functions with descriptive
  16750.     //    names. -- JW
  16751.     // Refactoring into several functions is in progress. -- JW
  16752.     su_refreshing_pagemeta = false;
  16753.  
  16754.     if (su_new_user)
  16755.         return;
  16756.     
  16757.     var doc = getBrowser().contentDocument;
  16758.     var new_url = su_get_browser_url(doc);
  16759.     var raw_url = su_get_browser_url(doc, true);
  16760.     var new_tld;
  16761.     var rateable = false;
  16762.     var rec_url = null;
  16763.     var url_detail = null;
  16764.     var stumblevideo = su_is_matching_domain(raw_url, "video." + su_servername);
  16765.     if (stumblevideo && (! from_stumblevideo_page))
  16766.         su_stumblevideo_page(doc, false);
  16767.     
  16768.     try {
  16769.         if (! url_detail)
  16770.             url_detail = su_ds.lookup("url:url_detail", new_url);
  16771.         
  16772.         if (url_detail)
  16773.         {
  16774.             new_url = url_detail.url;
  16775.             new_tld = url_detail.tld;
  16776.             rateable = true;
  16777.             rec_url = url_detail.url;
  16778.         }
  16779.         else if (stumbleid)
  16780.         {
  16781.             new_tld = su_get_tld(new_url);
  16782.             rateable = su_is_url_rateable(new_url, new_tld);
  16783.             if (su_ds.lookup("url:from_portal_flag", new_url))
  16784.             {
  16785.                 rec_url = new_url;
  16786.             }
  16787.             else if (su_get_tld(su_get_browser_referrer_url(doc)) == su_servername)
  16788.             {
  16789.                 su_ds.define("url:from_portal_flag", new_url, 1);
  16790.                 rec_url = new_url;
  16791.             }
  16792.         }
  16793.     } catch (e) { su_log_error("PAGEVIEW DETAILLOOKUP", e); }
  16794.     
  16795.     if (su_promo_mode && (stumbleid == 0))
  16796.     {
  16797.         
  16798.         try {
  16799.             su_update_website_info_promo(new_url);
  16800.         } catch (e) { su_log_error("PAGEVIEW INFOPROMO", e); }
  16801.         
  16802.         try {
  16803.             if (su_get_stumblevideo_detail())
  16804.                 su_set_visible("su_thumbdown", true);
  16805.             else
  16806.                 su_set_visible("su_thumbdown", false);
  16807.     
  16808.             //!!! we do enable all the time to fix thet problem where sometimes the comment button doesn't get cleared?
  16809.             if (typeof(su_ratings[new_url]) != "undefined")
  16810.                 su_disable_toolbar(su_ratings[new_url]);
  16811.             else
  16812.                 su_enable_toolbar();
  16813.         } catch (e) { su_log_error("PAGEVIEW PROMORATEBUTTONS", e); }
  16814.         
  16815.         return;
  16816.     }
  16817.     else if (stumbleid == 0)
  16818.     {
  16819.         return;    
  16820.     }
  16821.     
  16822.     var stumbler_name = null; 
  16823.     
  16824.     if ((new_tld == su_servername) || (new_tld == 'stumbleupon.com'))
  16825.         stumbler_name = su_get_profile_nickname(new_url);
  16826.     
  16827.     if (stumbler_name)
  16828.         rec_url = new_url;
  16829.     
  16830.     var non_self_stumbler = (stumbler_name &&
  16831.             (stumbler_name != stumbleid) &&
  16832.             (stumbler_name != su_ds.getValue("$nick")));
  16833.  
  16834.     var browser = getBrowser().selectedBrowser;
  16835.     
  16836.     var tab_url_detail = (browser.su_url_detail) ? browser.su_url_detail : null;
  16837.     
  16838.     try {
  16839.         su_update_thru_domain(new_url, new_tld, url_detail, stumblevideo, false);
  16840.     } catch (e) { su_log_error("PAGEVIEW FAVICON", e); }
  16841.     try {
  16842.         su_update_message(tab_url_detail, url_detail, new_url, new_tld, stumblevideo);
  16843.     } catch (e) { su_log_error("PAGEVIEW MESSAGE", e); }
  16844.     try {
  16845.         su_update_page_feature_prompt(new_url);
  16846.     } catch (e) { su_log_error("PAGEVIEW FEATUREPROMPT", e); }
  16847.     try {
  16848.         su_update_firstrater(url_detail);
  16849.     } catch (e) { su_log_error("PAGEVIEW FIRSTRATER", e); }
  16850.     try {
  16851.         su_update_topic_and_reporting(tab_url_detail, url_detail, new_tld, false, rec_url);
  16852.     } catch (e) { su_log_error("PAGEVIEW TOPIC", e); }
  16853. //    try {
  16854. //        su_update_language(url_detail, false);
  16855. //    } catch (e) { su_log_error("PAGEVIEW LANGUAGE", e); }
  16856.     try {
  16857.         su_update_comment_level(url_detail, rateable);
  16858.     } catch (e) { su_log_error("PAGEVIEW COMMENT", e); }
  16859.     try {
  16860.         su_update_referral_menu_tooltip(url_detail, stumblevideo);
  16861.     } catch (e) { su_log_error("PAGEVIEW TOOLTIP", e); }
  16862.     try {
  16863.         su_update_thumbs(new_url, rateable, non_self_stumbler, stumblevideo, url_detail);
  16864.     } catch (e) { su_log_error("PAGEVIEW THUMBS", e); }
  16865.     try {
  16866.         su_update_stumbling_options(non_self_stumbler, stumbler_name); 
  16867.     } catch (e) { su_log_error("PAGEVIEW STUMBLER", e); }
  16868.     try {
  16869.         su_update_tags(new_url)
  16870.     } catch (e) { su_log_error("PAGEVIEW TAGS", e); }
  16871.     
  16872.     
  16873.     // See if this is a tag page
  16874.     // only do this is text is on
  16875.     var tag_page = 0;
  16876.     var tag_name = '';
  16877.  
  16878.     try {
  16879.         if (new_url.indexOf(su_base_url + "tag/") == 0)
  16880.         {
  16881.             spliturl = new_url.split("/");
  16882.             if (spliturl.length > 4 && spliturl[4] != '')
  16883.             {
  16884.                 tag_name = spliturl[4];
  16885.                 //alert("tag " + tag_name);
  16886.                 tag_page = 1;
  16887.             }
  16888.         }
  16889.     
  16890.         if (tag_page)
  16891.         {
  16892.             // change favorites of
  16893.             el = su_get_element("su_cat_stumble_tags");
  16894.             if (el)
  16895.             {
  16896.                 el.setAttribute("label", "Through " + tag_name + "...");
  16897.                 el.setAttribute("oncommand", "su_select_topic('TAG_" + tag_name + "', '" + tag_name + "', false);");
  16898.                 el.setAttribute("tooltiptext", stumbler_name + "'s Pages");                
  16899.             }
  16900.             su_set_image("su_category", "chrome://stumbleupon/content/skin/tag.png");
  16901.         }
  16902.         else
  16903.         {
  16904.             el = su_get_element("su_cat_stumble_tags");
  16905.             if (el)
  16906.             {
  16907.                 el.setAttribute("label", "Search");
  16908.                 el.setAttribute("oncommand", 'su_handle_mode_click(event, "Search");');
  16909.                 el.setAttribute("tooltiptext", "Stumble within a query");
  16910.             }
  16911.         }
  16912.     } catch (e) { su_log_error("PAGEVIEW TAG", e); }
  16913.  
  16914.  
  16915.     try {
  16916.         // Reset message when we hit the message page
  16917.         if (new_url.indexOf("." + su_servername + "/inbox/")!=-1)
  16918.         {
  16919.             su_ds.setValue("$newmessage", false);
  16920.             su_set_inbox_status('');
  16921.         }
  16922.     } catch (e) { su_log_error("PAGEVIEW INBOX", e); }
  16923.  
  16924.  
  16925.     setTimeout("su_reflow_toolbar(15)", 80);
  16926.     
  16927. }
  16928.  
  16929. function su_update_thumbs(url, rateable, non_self_stumbler, stumblevideo, url_detail)
  16930. {
  16931.     if (stumblevideo)
  16932.         su_get_element("su_thumbdown").type = "";
  16933.     else
  16934.         su_get_element("su_thumbdown").type = "menu-button";
  16935.     
  16936.     var rating;
  16937.     if (rateable)
  16938.         rating = su_get_rating(url, stumblevideo, url_detail);
  16939.     else
  16940.         rating = null;
  16941.     
  16942.     //!!! we do enable all the time to fix thet problem where sometimes the comment button doesn't get cleared?
  16943.     if (rating == null)
  16944.         su_enable_toolbar();
  16945.     else
  16946.         su_disable_toolbar(rating);
  16947.         
  16948.     // disable rating buttons on url pages
  16949.     if (rateable)
  16950.     {
  16951. //            su_get_element("su_thumbdown").disabled=false;
  16952.         // if the thumb isn't green, we should enable it
  16953.         su_get_element("su_thumbup").disabled=false;
  16954.         su_get_element("su_thumbdown").disabled=false;
  16955.         su_get_element("su_thumbup").setAttribute("onclick", su_get_element("su_thumbup").getAttribute("onclick2"));
  16956.     }
  16957.     else
  16958.     {
  16959.         // disable rating buttons
  16960.         su_get_element("su_thumbup").disabled=true;
  16961.         su_get_element("su_thumbdown").disabled=true;
  16962.         su_get_element("su_thumbup").setAttribute("onclick", "");
  16963.     }
  16964.     
  16965.     if (su_ds.getValue("$icons") != "icons-only")
  16966.     {
  16967.         if (non_self_stumbler)
  16968.             su_set_label("su_thumbup", su_get_element("su_thumbup").getAttribute('showlabel2'));
  16969.         
  16970.         else            
  16971.             su_set_label("su_thumbup", su_get_element("su_thumbup").getAttribute('showlabel'));
  16972.     }
  16973. }
  16974.  
  16975. function su_update_tags(new_url)
  16976. {
  16977.     var tag_list = su_get_tag_list(new_url);
  16978.     
  16979.     if (tag_list)
  16980.         su_disable_tag_toolbar(tag_list);
  16981.     else
  16982.         su_enable_tag_toolbar();
  16983. }
  16984.  
  16985. function su_update_stumbling_options(non_self_stumbler, stumbler_name)
  16986. {
  16987.     var el;
  16988.     
  16989.     if (non_self_stumbler)
  16990.     {
  16991.         el = su_get_element("su_cat_favorites_of2");
  16992.         if (el)
  16993.         {
  16994.             el.setAttribute("label", stumbler_name + "'s Favorites");
  16995.             el.setAttribute("onclick", 'su_handle_mode_click(event, "' + stumbler_name + '");');
  16996.             el.setAttribute("tooltiptext", stumbler_name + "'s favorites");                
  16997.             if (su_is_mutual_friend(stumbler_name))
  16998.                 el.setAttribute("image", "chrome://stumbleupon/content/skin/mutual_favorites.png");
  16999.             else
  17000.                 el.setAttribute("image", "chrome://stumbleupon/content/skin/stumbler_favorites.png");
  17001.             el.setAttribute("hidden", "false");
  17002.         }
  17003.  
  17004.         el = su_get_element("su_mode_stumbler");
  17005.         el.setAttribute("tooltiptext", "Stumble " + stumbler_name + "'s favorites");
  17006.         el.setAttribute("onclick", 'su_handle_mode_click(event, "' + stumbler_name + '");');
  17007.         if (su_is_mutual_friend(stumbler_name))
  17008.             su_set_image("su_mode_stumbler", "chrome://stumbleupon/content/skin/mutual_favorites.png");
  17009.         else
  17010.             su_set_image("su_mode_stumbler", "chrome://stumbleupon/content/skin/stumbler_favorites.png");
  17011.         su_set_visible("su_mode_stumbler", true);
  17012.     }
  17013.     else
  17014.     {
  17015.         el = su_get_element("su_cat_favorites_of2");
  17016.         if(el)
  17017.         {
  17018.             el.setAttribute("hidden", "true");
  17019.         }
  17020.         
  17021.         su_set_visible("su_mode_stumbler", (! su_ds.getValue("$show_mode_stumbler")));
  17022.     }
  17023. }
  17024.  
  17025. function su_get_profile_nickname(url)
  17026. {
  17027.     var domain = su_get_tld(url);
  17028.     
  17029.     if (domain == 'stumbleupon.com')
  17030.     {
  17031.         var spliturl = url.split("/");
  17032.         
  17033.         var domains = spliturl[2].split(".");
  17034.         
  17035.         if (domains.length != 3)
  17036.             return null;
  17037.             
  17038.         if (su_ds.lookup("nickname:bad_nick_flag", domains[0]))
  17039.             return null;
  17040.         
  17041.         return domains[0];
  17042.     }
  17043.     else if ((su_servername != 'stumbleupon.com')
  17044.             && (domain == su_servername))
  17045.     {
  17046.         var spliturl = url.split("/");
  17047.         
  17048.         var domains = spliturl[2].split(".");
  17049.         
  17050.         var serverparts = su_servername.split(".");
  17051.  
  17052.         if (domains.length != (serverparts.length + 1))
  17053.             return null;
  17054.             
  17055.         if (su_ds.lookup("nickname:bad_nick_flag", domains[0]))
  17056.             return null;
  17057.         
  17058.         return domains[0];
  17059.     }
  17060.     else
  17061.     {
  17062.         return null;
  17063.     }
  17064. }
  17065.  
  17066. function su_get_service_id(url, results_page_only)
  17067. {
  17068.     if (! url.match(/(google|yahoo|ask|myspace|youtube|flickr|wikipedia|aol|cnn|bing|nytimes|cbsnews|cnet|abcnews|msnbc)/i))
  17069.         return null;
  17070.     
  17071.     url = url.toLowerCase();
  17072.     
  17073.     if (url.match(/^http.*?\/\/[^\/]*?(news\.google\.[^\.]+|news\.google\.co\.[^\.]+)\/(news.*[?&]q=)/))
  17074.         return "googlenews";
  17075.  
  17076.     else if (url.match(/^http.*?\/\/(news\.google\.[^\.]+|news\.google\.co\.[^\.]+)/))
  17077.         return "googlenewsindex";
  17078.  
  17079.     else if (url.match(/^http.*?\/\/[^\/]*?(video\.google\.[^\.]+|video\.google\.co\.[^\.]+)\/(videosearch.*[?&]q=)/))
  17080.         return "googlevideo";
  17081.     
  17082.     if (url.match(/^http.*?\/\/[^\/]*?(google\.[^\.]+|google\.co\.[^\.]+)\/((search|custom).*[?&](q|as_q)=)/))
  17083.         return "google";
  17084.  
  17085.     else if (url.match(/^http.*?\/\/[^\/]*?(google\.[^\.]+|google\.co\.[^\.]+)(\/$|webhp|#hl)/))
  17086.         return "google-ajax";
  17087.  
  17088.     else if (url.match(/^http.*?\/\/[^\/]*?(www\.ask\.com)\/(web.*[?&]q=)/))
  17089.         return "ask";
  17090.     
  17091.     else if (url.match(/^http.*?\/\/[^\/]*?(www\.bing\.com)\/(search.*?q=)/))
  17092.         return "bing";
  17093.     
  17094.     else if (url.match(/^http.*?\/\/[^\/]*?(www\.bing\.com)\/news\/(search.*?q=)/))
  17095.         return "bing-news";
  17096.     
  17097.     else if (url.match(/^http.*?\/\/[^\/]*?((search|custom)(\.)(.*(\.))?yahoo(\.).*)\/(search.*[?&]p=)/))
  17098.         return "yahoo";
  17099.  
  17100.     else if (url.match(/^http.*?\/\/[^\/]*?(search(\.)(.*(\.))?aol(\.).*)\/(search.*[?&]query=)/))
  17101.         return "aol";
  17102.     
  17103.     else if (url.match(/^http.*?\/\/[^\/]*?(searchservice\.myspace\.com)\/.*[?&]fuseaction=sitesearch\.results/))
  17104.         return "myspace";
  17105.     
  17106.     else if (url.match(/^http.*?\/\/[^\/]*?(youtube\.com)\/results.*[?&]search_query=/))
  17107.         return "youtube";
  17108.     
  17109.     else if (url.match(/^http.*?\/\/[^\/]*?flickr\.[^\.]+\/(search|.*[?&]q=)/))
  17110.         return "flickr";
  17111.     
  17112.     else if (url.match(/^http.*?\/\/[^\/]*\.wikipedia\.org\/wiki\//))
  17113.         return "wikipedia";
  17114.     
  17115.     else if (url.match(/^http:\/\/search\.cnn\.com\/search.*[?&]query=/))
  17116.         return "cnn";
  17117.     
  17118.     else if (url.match(/^http:\/\/query\.nytimes\.com\/search\/.*[?&]query=/))
  17119.         return "nyt";
  17120.     
  17121.     else if (url.match(/^http.*?\/\/(search|www)\.cbsnews\.com.*[?&]query=/))
  17122.         return "cbsnews";
  17123.     
  17124.     else if (url.match(/^http.*?\/\/news\.cnet\.com.*[?&]query=/))
  17125.         return "cnetnews";
  17126.     
  17127.     else if (url.match(/^http.*?\/\/abcnews\.go\.com.*[?&]searchtext=/))
  17128.         return "abcnews";
  17129.     
  17130.     else if (url.match(/^http:\/\/([^\.]*?\.)?msnbc\.msn\.com\/.*[?&]q=/))
  17131.         return "msnbc";
  17132.     
  17133.     else if (results_page_only)
  17134.         return null;
  17135.  
  17136.     else if (url.match(/^http.*?\/\/((www|news|video)\.google\.[^\.]+|(www|news|video)\.google\.co\.[^\.]+)/))
  17137.         return "google";
  17138.     
  17139.     else if (url.indexOf("http://www.ask.com") == 0)
  17140.         return "ask";
  17141.     
  17142.     else if (url.indexOf("http://www.yahoo.com") == 0)
  17143.         return "yahoo";
  17144.     
  17145.     else if (url.indexOf("http://www.aol.com") == 0)
  17146.         return "aol";
  17147.     
  17148.     else
  17149.         return null;
  17150.  
  17151.     
  17152. // Porting search page filters from the iebar follows the general 
  17153. // pattern below.  Note that migrating from strings to literal regular
  17154. // expressions involves changing some escaping.
  17155. //        else if (url.match(/^http.*?\/\/[^/]*?(URL_HOST_MATCH)/(PATH_MATCH)/))
  17156. // -- JW
  17157. }
  17158.  
  17159. function su_get_service_meta(url, results_page_only)
  17160. {
  17161.     var service_id = su_get_service_id(url, results_page_only);
  17162.  
  17163.     if (! service_id)
  17164.         return null;
  17165.  
  17166.     var detail = new Object();
  17167.     
  17168.     detail.id = service_id;    
  17169.     switch (service_id)
  17170.     {
  17171.         case "google":
  17172.         case "google-ajax":
  17173.         case "googlevideo":
  17174.         case "googlenews":
  17175.         case "googlenewsindex":
  17176.             detail.name = "Google";
  17177.             detail.icon = "chrome://stumbleupon/content/skin/favicon_google.png";
  17178.             break;
  17179.         case "ask":
  17180.             detail.name = "Ask";
  17181.             detail.icon = "chrome://stumbleupon/content/skin/favicon_ask.png";
  17182.             break;
  17183.         case "bing":
  17184.             detail.name = "Bing";
  17185.             detail.icon = "chrome://stumbleupon/content/skin/bubble.png";
  17186.             break;
  17187.         case "yahoo":
  17188.             detail.name = "Yahoo";
  17189.             detail.icon = "chrome://stumbleupon/content/skin/favicon_yahoo.png";
  17190.             break;
  17191.         case "aol":
  17192.             detail.name = "AOL";
  17193.             detail.icon = "chrome://stumbleupon/content/skin/favicon_aol.png";
  17194.             break;
  17195.         case "youtube":
  17196.             detail.name = "YouTube";
  17197.             detail.icon = "chrome://stumbleupon/content/skin/favicon_youtube.png";
  17198.             break;
  17199.         case "flickr":
  17200.             detail.name = "Flickr";
  17201.             detail.icon = "chrome://stumbleupon/content/skin/favicon_flickr.png";
  17202.             break;
  17203.         default:
  17204.             detail = null;
  17205.             break;
  17206.     }
  17207.     
  17208.     if (detail)
  17209.     {
  17210.         detail.prompt_label = "See ratings on " + detail.name;
  17211.         detail.prompt_tooltip = "See who likes your " + detail.name + " search results";
  17212.     }
  17213.     
  17214.     return detail;
  17215. }
  17216.  
  17217. function su_get_search_query_detail(opt_service_id, opt_url)
  17218. {
  17219.     var url;
  17220.     if (opt_url)
  17221.         url = opt_url;
  17222.     else
  17223.         url = su_get_browser_url();
  17224.     
  17225.     var service_id;
  17226.     if (opt_service_id)
  17227.         service_id = opt_service_id;
  17228.     else
  17229.         service_id = su_get_service_id(url, true);
  17230.     
  17231.     var detail = new Object();
  17232.     detail.term_count = 0;
  17233.     detail.is_query_results = false;
  17234.     detail.is_short_query_results = false;
  17235.     detail.is_first_page = true;
  17236.     detail.domain = su_get_domain(url);
  17237.     detail.service_id = service_id;
  17238.     
  17239.     var query_match;
  17240.     var page_match;
  17241.     switch (service_id)
  17242.     {
  17243.         case "google":
  17244.         case "google-ajax":
  17245.         case "googlenews":
  17246.         case "googleindex":
  17247.         case "googlevideo":
  17248.             page_match = url.match(/[?&](start=)/);
  17249.             query_match = url.match(/[?&]q=([^&]*)/);
  17250.             break;
  17251.         case "ask":
  17252.             page_match = url.match(/[?&](page=)/);
  17253.             query_match = url.match(/[?&]q=([^&]*)/);
  17254.             break;
  17255.         case "bing":
  17256.             page_match = url.match(/[?&](first=)/);
  17257.             query_match = url.match(/[?&]q=([^&]*)/);
  17258.             break;
  17259.         case "yahoo":
  17260.             page_match = url.match(/[?&](b=)/);
  17261.             query_match = url.match(/[?&]p=([^&]*)/);
  17262.             break;
  17263.         case "aol":
  17264.             page_match = url.match(/[?&](page=)/);
  17265.             query_match = url.match(/[?&]query=([^&]*)/);
  17266.             break;
  17267.     }
  17268.     
  17269.     if (query_match && query_match[1])
  17270.         detail.term_count = query_match[1].split("+").length;
  17271.  
  17272.     if (query_match)
  17273.         detail.is_query_results = true;
  17274.     
  17275.     if ((detail.term_count > 0) && (detail.term_count < 3))
  17276.         detail.is_short_query_results = true;
  17277.     
  17278.     if (page_match && page_match[1])
  17279.         detail.is_first_page = false;
  17280.     
  17281.     return detail;
  17282. }
  17283.  
  17284. // handles the DOMContentLoaded event
  17285. function su_on_load_page(event)
  17286. {
  17287.     var doc = event.target;
  17288.     var url;
  17289.     try {
  17290.         url = su_get_browser_url(doc).toLowerCase();
  17291.     } catch (e) { return; }
  17292.     
  17293.     try {
  17294.         var win = doc.defaultView.wrappedJSObject;
  17295.         if (win.top != win)
  17296.             return;
  17297.     } catch (e) {}
  17298.     
  17299.     var tld = su_get_tld(url);
  17300.     var portal_http = false;
  17301.     var portal_tld = false;
  17302.     
  17303.     if (tld == su_servername)
  17304.     {
  17305.         portal_tld = true;
  17306.         
  17307.         su_attach_api(doc);
  17308.         
  17309.         su_wire_portal_links(doc);
  17310.  
  17311.         if (su_visited_login_page)
  17312.             su_login_page_after();
  17313.         
  17314.         if (su_is_server_page(url, ""))
  17315.         {
  17316.             portal_http = true;
  17317.             
  17318.             // signup.php -- the page we send them to
  17319.             if (su_is_server_page(url, "signup.php"))
  17320.                 su_signup_page(doc);
  17321.             
  17322.             // sign_up.php -- the page they go to if they click "Join stumbleupon"
  17323.             // from the web site
  17324.             else if (su_is_server_page(url, "sign_up.php"))
  17325.                 su_sign_up_page(url);
  17326.             
  17327.             else if (su_is_server_page(url, "find_friends.php"))
  17328.                 su_find_friends_page(url);
  17329.             
  17330.             else if (su_is_server_page(url, "login.php"))
  17331.                 su_login_behavior_page();
  17332.         }
  17333.         else if (su_is_matching_domain(url, "video." + su_servername))
  17334.         {
  17335.             su_stumblevideo_page(doc, true);
  17336.         }
  17337.     }
  17338.     else if (tld == "facebook.com")
  17339.     {
  17340.         su_facebook_page(doc, url);
  17341.     }
  17342.     
  17343.     setTimeout(su_check_progress_listener, 0);
  17344.     
  17345.     if (stumbleid == 0)
  17346.         return;
  17347.     
  17348.     if (su_has_searchbox)
  17349.     {
  17350.         setTimeout(su_restore_searchbox_focus, 100);
  17351.         setTimeout(su_restore_searchbox_focus, 300);
  17352.         setTimeout(su_restore_searchbox_focus, 1000);
  17353.         setTimeout(su_restore_searchbox_focus, 3000);
  17354.     }
  17355.     
  17356.     var search_results_service_id = su_get_service_id(url, true);
  17357.     var search_service_id =  su_get_service_id(url, false);
  17358.     
  17359.     if (search_results_service_id)
  17360.         su_search_results_page(doc, search_results_service_id);
  17361.     
  17362.     else if (search_service_id)
  17363.         su_search_service_page(doc, search_service_id);
  17364.     
  17365.     else if (portal_http)
  17366.     {
  17367.         su_portal_http_page(doc);
  17368.         
  17369.         if (url.indexOf(su_serverhttp + "tag/") == 0)
  17370.             su_tag_page(doc);
  17371.  
  17372.         else if (url.indexOf(su_serverhttp + "find_friends_after.php") == 0)
  17373.             su_find_friends_after_page();
  17374.     
  17375.         else if (url.indexOf(su_serverhttp + "interests_after.php") == 0)
  17376.             su_legacy_interests_after_page(doc);
  17377.         
  17378.         else if (url.indexOf(su_serverhttp + "topic/") == 0)
  17379.             su_tag_page(doc);
  17380.     }
  17381.     
  17382.     else if (portal_tld)
  17383.     {
  17384.         var host = su_ds.getValue("$nick").toLowerCase() + "." + su_servername + "/";
  17385.         var profilehttp = "http://" + host;
  17386.         var profilehttps = "https://" + host;
  17387.         if ((url.indexOf(profilehttp + "prefs/interests")==0) ||
  17388.             (url.indexOf(profilehttps + "prefs/interests")==0))
  17389.             su_interests_page(doc);
  17390.         else if ((url.indexOf(profilehttp + "prefs/" )==0) ||
  17391.                 (url.indexOf(profilehttps + "prefs/" )==0))
  17392.             su_prefs_page(doc);
  17393.     }
  17394.     
  17395.     su_refresh_pagemeta(false, 7);
  17396. }
  17397.  
  17398. function su_get_debug_header()
  17399. {
  17400.     var datasource = su_get_service(
  17401.                 "@mozilla.org/extensions/manager;1",
  17402.                 "nsIExtensionManager")
  17403.                 .datasource;
  17404.     
  17405.     var root = su_get_rdf_resource("urn:mozilla:item:root");
  17406.     var container = su_create_instance(
  17407.                 "@mozilla.org/rdf/container;1",
  17408.                 "nsIRDFContainer");
  17409.     container.Init(datasource, root);
  17410.     var elements = container.GetElements();
  17411.  
  17412.     var attributes = new Array(
  17413.                 "name",
  17414.                 "version",
  17415.                 "appDisabled",
  17416.                 "userDisabled");
  17417.                 
  17418.     var gm_detail = null;
  17419.     var ns_detail = null;
  17420.     while(elements.hasMoreElements())
  17421.     {
  17422.         var element = elements.getNext();
  17423.         var item = new Object();
  17424.         for (i = 0; i < attributes.length; i++)
  17425.         {
  17426.             item[attributes[i]] = su_get_rdf_arc_literal(
  17427.                         datasource,
  17428.                         element,
  17429.                         "http://www.mozilla.org/2004/em-rdf#" + attributes[i]);
  17430.         }
  17431.  
  17432.         var type_id = su_get_rdf_arc_int(
  17433.                     datasource,
  17434.                     element,
  17435.                     "http://www.mozilla.org/2004/em-rdf#type");
  17436.         
  17437.         if (type_id == 2 && item.name && item.name == "Greasemonkey")
  17438.         {
  17439.             gm_detail = new Object();
  17440.             gm_detail.version = item.version;
  17441.             gm_detail.enabled = (item.appDisabled || item.userDisabled) ? 0 : 1;
  17442.         }
  17443.         else if (type_id == 2 && item.name && item.name == "NoScript")
  17444.         {
  17445.             ns_detail = new Object();
  17446.             ns_detail.version = item.version;
  17447.             ns_detail.enabled = (item.appDisabled || item.userDisabled) ? 0 : 1;
  17448.         }
  17449.         
  17450.         if (gm_detail && ns_detail)
  17451.             break;
  17452.     }
  17453.     
  17454.     if ((! gm_detail) && (! ns_detail))
  17455.         return null;
  17456.     
  17457.     var obj = new Object();
  17458.  
  17459.     if (gm_detail)
  17460.     {
  17461.         if (su_ds.isPrefDefined("greasemonkey.enabled"))
  17462.             gm_detail.running = (su_ds.getValue("greasemonkey.enabled")) ? 1 : 0;
  17463.             
  17464.         var scripts = su_get_gm_scripts();
  17465.         if (scripts)
  17466.             gm_detail.scripts = scripts;
  17467.  
  17468.         obj.greasemonkey = gm_detail;
  17469.     }
  17470.     
  17471.     if (ns_detail)
  17472.     {
  17473.         if (su_ds.isPrefDefined("noscript.global"))
  17474.             ns_detail.running = (su_ds.getValue("noscript.global")) ? 0 : 1;
  17475.  
  17476.         obj.noscript = ns_detail;
  17477.     }
  17478.     
  17479.     return su_ds.serialize(obj, false);
  17480. }
  17481.  
  17482. function su_get_noscript_enabled_version()
  17483. {
  17484.     if ((typeof noscriptUtil) != "object")
  17485.         return false;
  17486.     
  17487.     var datasource = su_get_service(
  17488.                 "@mozilla.org/extensions/manager;1",
  17489.                 "nsIExtensionManager")
  17490.                 .datasource;
  17491.     
  17492.     var root = su_get_rdf_resource("urn:mozilla:item:root");
  17493.     var container = su_create_instance(
  17494.                 "@mozilla.org/rdf/container;1",
  17495.                 "nsIRDFContainer");
  17496.     container.Init(datasource, root);
  17497.     var elements = container.GetElements();
  17498.  
  17499.     var attributes = new Array(
  17500.                 "name",
  17501.                 "version",
  17502.                 "appDisabled",
  17503.                 "userDisabled");
  17504.                 
  17505.     while(elements.hasMoreElements())
  17506.     {
  17507.         var element = elements.getNext();
  17508.         var item = new Object();
  17509.         for (i = 0; i < attributes.length; i++)
  17510.         {
  17511.             item[attributes[i]] = su_get_rdf_arc_literal(
  17512.                         datasource,
  17513.                         element,
  17514.                         "http://www.mozilla.org/2004/em-rdf#" + attributes[i]);
  17515.         }
  17516.  
  17517.         var type_id = su_get_rdf_arc_int(
  17518.                     datasource,
  17519.                     element,
  17520.                     "http://www.mozilla.org/2004/em-rdf#type");
  17521.         
  17522.         if (type_id == 2 && item.name && item.name == "NoScript" &&
  17523.                 (! item.appDisabled) && (! item.userDisabled))
  17524.         {
  17525.             return item.version;
  17526.         }
  17527.     }
  17528.     return null;
  17529. }
  17530.  
  17531. //
  17532. // su_dotversion_compare
  17533. //
  17534. // Compares two version numbers of the form a.b.c.d.
  17535. // Results are:
  17536. //    ver1 > ver2  : +1
  17537. //    ver1 < ver2  : -1
  17538. //    ver1 == ver2 : 0
  17539. //    poorly formatted version number : null
  17540. //
  17541. // If they are different lengths, for example:
  17542. //     1.9.3
  17543. //     1.9.3.4
  17544. // Then the longer version is considered larger.
  17545. //
  17546. function su_dotversion_compare(ver1, ver2)
  17547. {
  17548.     var parts1 = ver1.split(".");
  17549.     var parts2 = ver2.split(".");
  17550.     
  17551.     for(var i=0; (i < parts1.length) && (i < parts2.length); i++)
  17552.     {
  17553.         var n1 = parseInt(parts1[i]);
  17554.         var n2 = parseInt(parts2[i]);
  17555.         if(isNaN(n1) || isNaN(n2))
  17556.             return null;
  17557.         
  17558.         if(n1 > n2)
  17559.             return 1;
  17560.         else if(n1 < n2)
  17561.             return -1;
  17562.     }
  17563.     
  17564.     if(i == 0)
  17565.         return null;
  17566.     
  17567.     if(parts1.length > parts2.length)
  17568.         return 1;
  17569.     else if(parts1.length < parts2.length)
  17570.         return -1;
  17571.     else
  17572.         return 0;
  17573. }
  17574.  
  17575. function su_get_gm_scripts()
  17576. {
  17577.     var file = su_get_service(
  17578.                 "@mozilla.org/file/directory_service;1",
  17579.                 "nsIProperties")
  17580.                 .get("ProfD", Components.interfaces.nsILocalFile);
  17581.     file.append("gm_scripts");
  17582.     
  17583.     if (! file.exists())
  17584.     {
  17585.         file = su_ds.getChromeNSIFile("chrome://greasemonkey/content").parent;
  17586.         file.append("scripts");
  17587.     }
  17588.     
  17589.     file.append("config.xml");
  17590.     
  17591.     if (! file.exists())
  17592.         return null;
  17593.     
  17594.     var str = su_ds.readFile(file);
  17595.     
  17596.     if (str == "")
  17597.         return null;
  17598.     
  17599.     var doc = su_create_instance(
  17600.                 "@mozilla.org/xmlextras/domparser;1",
  17601.                 "nsIDOMParser")
  17602.                 .parseFromString(str, "text/xml");
  17603.     
  17604.     var nodes = doc.evaluate("/UserScriptConfig/Script", doc, null, 0, null);
  17605.  
  17606.     var scripts = new Array();
  17607.     var node;
  17608.     for (node = null; (node = nodes.iterateNext()); )
  17609.     {
  17610.         var detail = new Object();
  17611.  
  17612.         var i;
  17613.         var childNode;
  17614. //        detail.su = 0;
  17615. //        for (i = 0, childNode = null; (childNode = node.childNodes[i]); i++)
  17616. //        {
  17617. //            if (childNode.nodeName == "Include") 
  17618. //                detail.su = (childNode.firstChild.nodeValue.toLowerCase().indexOf("stumbleupon") != -1) ? 1 : 0;
  17619. //            
  17620. //            if (detail.su)
  17621. //                break;
  17622. //        }
  17623.         detail.name = node.getAttribute("name");
  17624.         detail.enabled = (node.getAttribute("enabled") == true.toString()) ? 1 : 0;
  17625.  
  17626.         scripts.push(detail);
  17627.     }
  17628.     
  17629.     return scripts;
  17630. }
  17631.  
  17632. function su_handle_prefetch_load_start()
  17633. {
  17634.     var original_target = su_prefetcher.getCurrentTarget();
  17635.     var ultimate_target = su_prefetcher.getRedirectTarget(original_target);
  17636.     var status = su_prefetcher.getHttpResponseStatus(original_target);
  17637.     
  17638.     if ((status == 301) || ((status == 302) && 
  17639.                 (su_get_tld(original_target) != su_get_tld(ultimate_target))))
  17640.     {
  17641.         // The url is a permanent redirect (301) or a 302 redirect
  17642.         // to a different domain.
  17643.         su_report_redirect(url, status, ultimate_target);
  17644.     }
  17645. }
  17646.  
  17647. function su_report_redirect(url, status, new_target)
  17648. {
  17649.     if (su_ds.lookup("url:reported_404_flag", url))
  17650.         return;
  17651.  
  17652.     su_ds.define("url:reported_404_flag", url, 1);
  17653.  
  17654.     var context = new Object();
  17655.     context.quiet = true;
  17656.     
  17657.     var params = "";
  17658.     params = su_arp(params, "url", url);
  17659.     params = su_arp(params, "status", status);
  17660.     params = su_arp(params, "newurl", new_target);
  17661.     
  17662.     su_post_url_server_async(
  17663.             "404.php",
  17664.             params,
  17665.             15000,
  17666.             su_generic_done,
  17667.             context);
  17668. }
  17669.  
  17670. function su_report_404(url, status)
  17671. {
  17672.     if (su_ds.lookup("url:reported_404_flag", url))
  17673.         return;
  17674.     
  17675.     su_ds.define("url:reported_404_flag", url, 1);
  17676.  
  17677.     var context = new Object();
  17678.     context.quiet = true;
  17679.     
  17680.     var params = "";
  17681.     params = su_arp(params, "url", url);
  17682.     params = su_arp(params, "status", status);
  17683.     
  17684.     su_post_url_server_async(
  17685.             "404.php",
  17686.             params,
  17687.             15000,
  17688.             su_generic_done,
  17689.             context);
  17690. }
  17691.  
  17692. function su_preload_images()
  17693. {
  17694.     var el = document.createElement("image");
  17695.     var id = "su_image_loader" + su_load_image_count;
  17696.     su_load_image_count++;
  17697.     el.setAttribute("id", id);
  17698.     el.setAttribute("src", "chrome://stumbleupon/content/skin/arrow_green-b.png");
  17699.     el.setAttribute("style", "visibility:hidden;border:0px solid black;width:0px;height:0px;");
  17700. }
  17701.  
  17702. function su_handle_resource_installed(event)
  17703. {
  17704.     var el = document.createElement("image");
  17705.     var id = "su_image_loader" + su_load_image_count;
  17706.     su_load_image_count++;
  17707.     el.setAttribute("src", 
  17708.                 su_ds.getResourceURLFromSourceURL(event.URL));
  17709.     el.setAttribute("id", id);
  17710.     el.setAttribute("style", "visibility:hidden;border:0px solid black;width:0px;height:0px;");
  17711.     el.setAttribute("onload", 'su_handle_resource_image_load(event, "' + event.URL + '", "' + id + '");');
  17712.     el.setAttribute("onerror", 'su_handle_resource_image_load(event, "' + event.URL + '", "' + id + '");');
  17713.     document.getElementById("main-window").appendChild(el);
  17714. }
  17715.  
  17716. function su_handle_resource_image_load(event, source_url, testid)
  17717. {
  17718.     var iconpic_regex = new RegExp("^http://cdn.stumble-upon.com/iconpics/(\\d*)\\.jpg$");
  17719.     var iconpic_match = source_url.match(iconpic_regex);
  17720.     var favicon_regex = new RegExp("^http://cdn.stumble-upon.com/images/stumblethru/(.*\\.ico)$");
  17721.     if (su_test_stumblethru_update)
  17722.         favicon_regex = new RegExp("^" + su_serverhttp + "images/stumblethru/(.*\\.ico)$");
  17723.     var favicon_match = source_url.match(favicon_regex);
  17724.     var searchlinks_regex = new RegExp("^http://cdn.stumble-upon.com/images/(.*searchlinks.*_prompt.gif)$");
  17725.     var searchlinks_match = source_url.match(searchlinks_regex);
  17726.     if (iconpic_match)
  17727.     {
  17728.         var contactid = iconpic_match[1];
  17729.         var contact = su_ds.selectRow("contact", "contactid", contactid);
  17730.         if (event.type == "load")
  17731.         {
  17732.             if (contact)
  17733.             {
  17734.                 contact.iconpic = su_get_time_s();
  17735.                 su_ds.updateRow(contact);
  17736.                 su_refresh_referral_menu(9);
  17737.             }
  17738.         }
  17739.         else
  17740.         {
  17741.             if (contact)
  17742.             {
  17743.                 contact.iconpic = 0;
  17744.                 su_ds.updateRow(contact);
  17745.             }
  17746.             su_ds.deleteFile(
  17747.                         su_ds.getResourceNSIFile("iconpics", contactid + ".jpg"));
  17748.         }
  17749.     }
  17750.     else if (searchlinks_match)
  17751.     {
  17752.         var filename = searchlinks_match[1];
  17753.         if (event.type == "load")
  17754.         {
  17755.             if (su_searchlinks_dialog_detail)
  17756.             {
  17757.                 var detail = su_searchlinks_dialog_detail;
  17758.                 su_searchlinks_dialog_detail = null;
  17759.                 su_handle_searchlinks_dialog_resource_load(detail);
  17760.             }
  17761.         }
  17762.         else
  17763.         {
  17764.             su_ds.setValue("$shown_searchlinks_dialog", false);
  17765.             su_ds.setValue("$show_searchlinks_score", false);
  17766.             su_ds.setValue("$show_searchlinks_friends", false);
  17767.             su_ds.setValue("$show_searchlinks_topic", false);
  17768.             su_ds.flushPrefs();
  17769.             su_ds.deleteFile(
  17770.                         su_ds.getResourceNSIFile("images", filename));
  17771.             if (su_searchlinks_dialog_detail)
  17772.             {
  17773.                 var detail = su_searchlinks_dialog_detail;
  17774.                 su_searchlinks_dialog_detail = null;
  17775.                 if (detail.stumble)
  17776.                     stumble(stumble.new_tab, true);
  17777.             }
  17778.         }
  17779.     }
  17780.     else if (favicon_match)
  17781.     {
  17782.         if (event.type == "load")
  17783.         {
  17784.             su_refresh_dyn_channels();
  17785.         }
  17786.         else
  17787.         {
  17788.             var filename = favicon_match[1];
  17789.             su_ds.deleteFile(
  17790.                         su_ds.getResourceNSIFile("favicons", filename));
  17791.         }
  17792.     }
  17793.     
  17794.     var el = document.getElementById(testid);
  17795.     el.parentNode.removeChild(el);
  17796. }
  17797.  
  17798. // in Firefox 1.5+, this observer service listener detects application
  17799. // event, like uninstalling the toolbar or quitting the application
  17800. var su_host_observer =
  17801. {
  17802.     observe : function(subject,topic,data)
  17803.     {
  17804.         subject = subject.QueryInterface(Components.interfaces.nsIUpdateItem);
  17805.  
  17806.         if ((topic == "em-action-requested") && (subject.name == "StumbleUpon") && 
  17807.                     (data == "item-uninstalled"))
  17808.         {
  17809.             su_handle_em_uninstall();
  17810.         }
  17811.     }
  17812. }
  17813.  
  17814. // each window's load() registers an event_observer; when a window 
  17815. // invokes an event using invoke_global_event(), the observerService 
  17816. // dispatches a notification to each event_observer
  17817. var su_event_observer =
  17818. {
  17819.     observe : function (subject, topic, data)
  17820.     {
  17821.         var detail = null;
  17822.         if (data && data != "")
  17823.             detail = su_ds.deserialize(data);
  17824.         
  17825.         switch (topic)
  17826.         {
  17827.             case "su_login":
  17828.                 var skip_cookies = (detail && detail.skip_cookies);
  17829.                 var ignore_cookies = (detail && detail.ignore_cookies);
  17830.                 var new_profile = (detail && detail.new_profile);
  17831.                 var new_user_prompt = (detail && detail.new_user_prompt);
  17832.                 su_login(skip_cookies, ignore_cookies, new_profile, new_user_prompt);
  17833.                 break;
  17834.             case "su_logout":
  17835.                 su_logout();
  17836.                 break;
  17837.             case "su_change-password":
  17838.                 su_change_password();
  17839.                 break;
  17840.             case "su_configure-toolbar":
  17841.                 var from_preference_dialog = (detail && detail.from_preference_dialog);
  17842.                 su_configure_toolbar(from_preference_dialog);
  17843.                 break;
  17844.             case "su_referral-menu-dirty":
  17845.                 su_referral_menu_dirty = true;
  17846.                 break;
  17847.             case "su_update-referral-menu":
  17848.                 su_update_referral_menu();
  17849.                 break;
  17850.             case "su_refresh-category-selector":
  17851.                 su_refresh_category_selector();
  17852.                 break;
  17853.             case "su_dyn-channels-dirty":
  17854.                 su_dyn_channels_dirty = true;
  17855.                 break;
  17856.             case "su_update-dyn-channels":
  17857.                 su_update_dyn_channels();
  17858.                 break;
  17859.             case "su_schedule-remove-data":
  17860.                 su_schedule_remove_data();
  17861.                 break;
  17862.             case "su_message-button-click":
  17863.                 su_handle_message_button_click(subject);
  17864.                 break;
  17865.         }
  17866.     }
  17867. }
  17868.  
  17869. function su_verify_cookie_perms(notify_upon_modify)
  17870. {
  17871.     if (! su_ds.isPrefDefined("network.cookie.cookieBehavior") || !su_ds.getValue("@auto_cookie_exceptions"))
  17872.         return;
  17873.     
  17874.     var supr_domain = su_ds.getValue("@supr_domain");
  17875.     var domains = new Array(su_servername, "video." + su_servername, supr_domain);
  17876.     
  17877.     var perm_man = su_get_service(
  17878.                 "@mozilla.org/permissionmanager;1",
  17879.                 "nsIPermissionManager");
  17880.     
  17881.     var modified = false;
  17882.     if (su_ds.getValue("network.cookie.cookieBehavior") != 0)
  17883.     {
  17884.         modified = true;
  17885.         var i;
  17886.         for (i = 0; i < domains.length; i++)
  17887.         {
  17888.             var nsiuri = su_get_nsiuri(domains[i]);
  17889.             perm_man.add(nsiuri, "cookie", perm_man.ALLOW_ACTION);
  17890.         }
  17891.     }
  17892.     
  17893.     if (modified && notify_upon_modify)
  17894.     {
  17895.         setTimeout(su_alert_cookie_change, 100);
  17896.     }
  17897. }
  17898.  
  17899. function su_alert_cookie_change()
  17900. {
  17901.     var ps = su_get_service(
  17902.                 "@mozilla.org/embedcomp/prompt-service;1",
  17903.                 "nsIPromptService");
  17904.     
  17905.     ps.alert(window,
  17906.                 "StumbleUpon",
  17907.                 "Exceptions to allow StumbleUpon cookies have been added.\n\n" + 
  17908.                 "This is required for the StumbleUpon toolbar to be fully functional.\n\n");
  17909. }
  17910.  
  17911. function su_gui_render()
  17912. {
  17913.     var test_ids = [
  17914.                 "su_render",
  17915.                 "su_overflow_popup",
  17916.                 "su_stumble_topic",
  17917.                 "su_page_feature_prompt",
  17918.                 "su_messages",
  17919.                 "firstrater",
  17920.                 "su_searchbox",
  17921.                 "su_category",
  17922.                 "su_referral_menu",
  17923.                 "su_website_info",
  17924.                 "su_thumbdown",
  17925.                 "su_thumbup",
  17926. //                "su_inbox-count",
  17927.                 "su_referred",
  17928.                 "su_stumble",
  17929.                 "su_splitter_first_flexbox",
  17930.                 "su_spacer"];
  17931.                 
  17932.     // keep trying until we find the gui
  17933.     var i;
  17934.     for (i = 0; i < test_ids.length; i++)
  17935.     {
  17936.         if (! su_get_element(test_ids[i]))
  17937.         {
  17938.             setTimeout("su_gui_render()", 100);
  17939.             return;
  17940.         }
  17941.     }
  17942.  
  17943.     
  17944. //    if ((su_get_element("su_render") == null) ||
  17945. //                (su_get_element("su_category") == null))
  17946. //    {
  17947. //        setTimeout("su_gui_render()", 100);
  17948. //        return;
  17949. //    }
  17950.     
  17951.     su_set_visible("su_bug", su_enable_message_log);
  17952.     
  17953.     // These configure toolbars correctly when opening a new browser
  17954.     // window after changing toolbar elements but before persisting.
  17955.     // There may be a better way to handle this, by figuring out how
  17956.     // to persist without breaking urlbar; for now it works. -- JW
  17957. //    try {
  17958. //        su_prevent_toolbar_sharing();
  17959. //    } catch (e) { su_log_error("INIT SHARING", e); }
  17960.     try {
  17961.         su_refresh_toggle_button(true);
  17962.     } catch (e) { su_log_error("INIT TOGGLE", e); }
  17963.     
  17964.     // Netscape 8.0.x needs a separator to push the stumble button past
  17965.     // the NS logo.
  17966.     if (su_host.netscape && (su_host.version.indexOf("8.0") != -1))
  17967.         su_get_element("su_spacer").collapsed = false;
  17968.  
  17969.     try {
  17970.         su_verify_cookie_perms(su_new_install);
  17971.     } catch (e) { su_log_error("ALLOW COOKIES", e); }
  17972.  
  17973.     if (su_new_install)
  17974.     {
  17975.         var loc = "firefox_start.php";
  17976.         if (su_host.dist)
  17977.             loc = "campus_start.php";
  17978.         
  17979.         su_set_server_location(loc, null, true);
  17980.  
  17981.         try {
  17982.             // block popups from external applications ( a major new source of unwanted popups )
  17983.             // Only do this once, in case they have a reason to set it back
  17984.             su_ds.setValue("privacy.popups.disable_from_plugins", 2);
  17985.             
  17986.         } catch (e) { su_log_error("PREPARE BROWSER", e); }
  17987.     }
  17988.     else if (su_new_upgrade && (su_private_label.indexOf("ALPHA") != 0) && 
  17989.                 (su_private_label.indexOf("BETA") != 0))
  17990.     {
  17991.         su_new_upgrade = false;
  17992.     }
  17993.     
  17994.     su_new_install = false;
  17995.     su_dist_time();
  17996.     
  17997.     var installed = su_ds.getIntValue("@installed");
  17998.     var now_s = su_get_time_s();
  17999. //    if ((now_s - installed) > (3600 * 24))
  18000. //        su_promo_mode = true;
  18001.  
  18002.     if (stumbleid == 0)
  18003.     {
  18004.         su_move_toolbar(true, 2);
  18005.         su_configure_toolbar(false);
  18006.         su_check_progress_listener();
  18007.     }
  18008.     else
  18009.     {
  18010.         su_show_searchlinks_dialog(false, false, false);
  18011.         su_load_data2(false);  // calls configure_toolbar()
  18012.     }
  18013.     
  18014.     if (window.onViewToolbarsPopupShowing)
  18015.     {
  18016.         // This is a bit tricky.  Basically, we're replacing a browser-
  18017.         // defined function with our own function.  For details, see the
  18018.         // comments in function 
  18019.         // su_replacement_onViewToolbarsPopupShowing.
  18020.         window.su_saved_onViewToolbarsPopupShowing = window.onViewToolbarsPopupShowing;
  18021.         window.onViewToolbarsPopupShowing = window.su_replacement_onViewToolbarsPopupShowing;
  18022.     }
  18023.     
  18024.     if (window.BrowserCustomizeToolbar)
  18025.     {
  18026.         // This is a bit tricky.  Basically, we're replacing a browser-
  18027.         // defined function with our own function.  For details, see the
  18028.         // comments in function 
  18029.         // su_replacement_onViewToolbarsPopupShowing.
  18030.         window.su_saved_BrowserCustomizeToolbar = window.BrowserCustomizeToolbar;
  18031.         window.BrowserCustomizeToolbar = window.su_replacement_BrowserCustomizeToolbar;
  18032.     }
  18033.  
  18034.     if (window.BrowserToolboxCustomizeDone)
  18035.     {
  18036.         // This hack is similar to the one above.  See function
  18037.         // su_replacement_BrowserToolboxCustomizeDone.
  18038.         window.su_saved_BrowserToolboxCustomizeDone = window.BrowserToolboxCustomizeDone;
  18039.         var toolbox = document.getElementById("navigator-toolbox");
  18040.         toolbox.customizeDone = window.su_replacement_BrowserToolboxCustomizeDone;
  18041.     }
  18042.     
  18043.     if (window.foxytunesSetFoxyTunesPosition)
  18044.     {
  18045.         window.su_saved_foxytunesSetFoxyTunesPosition = window.foxytunesSetFoxyTunesPosition;
  18046.         window.foxytunesSetFoxyTunesPosition = window.su_replacement_foxytunesSetFoxyTunesPosition;
  18047.     }    
  18048.     
  18049.     window.addEventListener("resize", su_handle_window_resize, false);
  18050.     window.addEventListener("focus", su_handle_window_focus, true);
  18051.     
  18052.     // for instances where we still need a load listener (such as interests_after.php)
  18053.     window.addEventListener("DOMContentLoaded", su_on_load_page, true);
  18054.  
  18055.     getBrowser().addEventListener("click", su_handle_content_click, false);
  18056.     
  18057. //    We may have to do this if onLocationChange stops working.
  18058. //    if (su_host.ff2plus)
  18059. //        getBrowser().tabContainer.addEventListener("TabSelect", su_handle_tabselect, false);
  18060.     
  18061.     su_gui_initialized = true;
  18062.     su_ds.prefRetries = 15;
  18063.     
  18064.     setTimeout("su_reflow_toolbar(3);", 0);
  18065.     setTimeout("su_reflow_toolbar(3);", 500);
  18066.     setTimeout("su_cleanup_toolbox(true, false)", 550);
  18067.     setInterval("su_process_quarter_hourly()", 15 * 60 * 1000);
  18068. }
  18069.  
  18070. //    We may have to do this if onLocationChange stops working.
  18071. //function su_handle_tabselect(event)
  18072. //{
  18073. //  su_refresh_pagemeta(false, 11);
  18074. //}
  18075.  
  18076. function su_photoBlogContext() 
  18077. {
  18078.     if (gContextMenu) 
  18079.     {
  18080.         menuitem = su_get_element('context-photoblog-ilikeit');
  18081.  
  18082.         if (menuitem)
  18083.         {
  18084.             menuitem.hidden = !gContextMenu.onImage;
  18085.             //alert("photo " + !gContextMenu.onImage);
  18086.             
  18087.         }
  18088.         // menuitem = su_get_element('context-photoblog-notforme');
  18089.         // if(menuitem)
  18090.         //     menuitem.hidden = !gContextMenu.onImage;
  18091.         
  18092.         // look for selected text
  18093.         var selectedText = su_getSelectedText(" ");
  18094. //        alert("?" + selectedText);
  18095.  
  18096.         if (selectedText != "")
  18097.         {
  18098.             // tag button    
  18099.             //!!! only do this if size isn't greater than maximum tag size...
  18100.             menuitem = su_get_element('context-stumble-tagit');
  18101.             menuitem.hidden = false;
  18102.             var selectedText2 = selectedText;
  18103.             if (selectedText2.length > 15)
  18104.                 selectedText2 = selectedText.substring(0, 15) + "...";    
  18105.             menuitem.label = "Tag this page as '" + selectedText2 + "'";
  18106.             menuitem.setAttribute("class", "menuitem-iconic");
  18107.             menuitem.setAttribute("image", "chrome://stumbleupon/content/skin/tag.png");        
  18108.             
  18109.             // search
  18110.             //!!! only do this if absolute enable_search == yes
  18111.             
  18112.             //!!! We've stopped prompting for enable_search, so we'll leave
  18113.             // it as is for now.
  18114.             
  18115.             menuitem = su_get_element('context-stumble-search');
  18116.             menuitem.hidden = false;
  18117.             selectedText2 = selectedText;
  18118.             if (selectedText2.length > 15)
  18119.                 selectedText2 = selectedText.substring(0, 15) + "...";    
  18120.             menuitem.label = "StumbleThru '" + selectedText2 + "'";
  18121.             menuitem.setAttribute("class", "menuitem-iconic");
  18122.             menuitem.setAttribute("image", "chrome://stumbleupon/content/skin/stumble.png");
  18123.         }
  18124.         else
  18125.         {
  18126.             menuitem = su_get_element('context-stumble-tagit');
  18127.             menuitem.hidden = true;
  18128.             
  18129.             menuitem = su_get_element('context-stumble-search');
  18130.             menuitem.hidden = true;
  18131.         }         
  18132.     }
  18133. }
  18134.  
  18135. function su_contextTag()
  18136. {
  18137.     var current_url = su_get_browser_url();
  18138.     var selectedText = su_getSelectedText(" ");
  18139.     su_get_element("su_searchbox").value = selectedText;
  18140.     su_tagit(current_url, selectedText, 0, su_get_title(), su_get_browser_url(null, true));
  18141. }
  18142.  
  18143. function su_contextSearch(event)
  18144. {
  18145.     var selectedText = su_getSelectedText(" ");
  18146.     su_old_search = selectedText;
  18147.     su_visited_searchbox = 1;
  18148.     
  18149.     su_get_element('su_searchbox').removeAttribute("mode");
  18150.  
  18151.     if (su_url_has_tag)
  18152.     {    
  18153.         su_url_has_tag = false;
  18154.         su_get_element('su_searchbox').value = '';
  18155.         su_get_element('su_searchbox').removeAttribute("mode");
  18156.  
  18157.         su_get_element("su_tag").image="chrome://stumbleupon/content/skin/tag.png";
  18158.         su_get_element('su_tag').setAttribute("tooltiptext", su_get_element('su_tag').getAttribute("tooltiptext2"));
  18159.         su_get_element("su_tag2").image="chrome://stumbleupon/content/skin/tag.png";
  18160.         su_get_element('su_tag2').setAttribute("tooltiptext", su_get_element('su_tag2').getAttribute("tooltiptext2"));
  18161.     }
  18162.     
  18163.     var searchbox = su_get_element("su_searchbox");
  18164.     searchbox.value = selectedText;
  18165.     if (! (searchbox.hasAttribute("focused") && 
  18166.                 (searchbox.getAttribute("focused") == "true")))
  18167.     {
  18168.         searchbox.focus();
  18169.     }
  18170.     
  18171.     var new_tab = su_new_tab(event);
  18172.     new_tab = new_tab || su_ds.getValue("$search_new_window");
  18173.     su_stumble_in_tag(selectedText, new_tab);    
  18174. }
  18175.  
  18176. function su_getSelectedText(concationationChar)
  18177. {
  18178.     var node = document.popupNode;
  18179.     var selection = "";
  18180.  
  18181.     if ((node instanceof HTMLTextAreaElement) || (node instanceof HTMLInputElement && node.type == "text"))
  18182.     {
  18183.         selection = node.value.substring(node.selectionStart, node.selectionEnd);
  18184.     } 
  18185.     else {
  18186.         var focusedWindow = new XPCNativeWrapper(document.commandDispatcher.focusedWindow, 'document', 'getSelection()');
  18187.         selection = focusedWindow.getSelection().toString();
  18188.     }
  18189.  
  18190.     // Limit length to 150 to optimize performance. Longer does not make sense
  18191.     if (selection.length>=150)
  18192.         selection = selection.substring(0, 149);
  18193.  
  18194.     selection = selection.replace(/(\n|\r|\t)+/g, " ");
  18195.     // Strip spaces at start and end.
  18196.     selection = selection.replace(/(^\s+)|(\s+$)/g, "");
  18197.  
  18198.     selection = selection.split(" ");
  18199.  
  18200.     // Remove certain characters at the beginning and end of every word
  18201.     for (i=0; i<selection.length; i++)
  18202.     {
  18203.         selection[i]=selection[i].replace(/^(\&|\(|\)|\[|\]|\{|\}|"|,|\.|!|\?|'|:|;)+/, "");
  18204.         selection[i]=selection[i].replace(/(\&|\(|\)|\[|\]|\{|\}|"|,|\.|!|\?|'|:|;)+$/, "");
  18205.     }   
  18206.     selection = selection.join(concationationChar);   
  18207.     return selection; 
  18208. }
  18209.  
  18210. function su_show_banner(prompt, icon, accept_callback, decline_callback)
  18211. {
  18212.     var box = getBrowser().getNotificationBox();
  18213.     var notification = box.getNotificationWithValue("su_message");
  18214.     if (notification)
  18215.         return;
  18216.     
  18217.     var buttons = new Array();
  18218.     
  18219.     buttons.push({
  18220.                 label: "Join StumbleUpon Now",
  18221.                 accessKey: "J",
  18222.                 popup: null,
  18223.                 callback: accept_callback});
  18224.     
  18225.     buttons.push({
  18226.                 label: "No thanks",
  18227.                 accessKey: "N",
  18228.                 popup: null,
  18229.                 callback: decline_callback});
  18230.     
  18231.     buttons.push({
  18232.                 label: "Later",
  18233.                 accessKey: "L",
  18234.                 popup: null,
  18235.                 callback: function(){}});
  18236.     
  18237.     const priority = box.PRIORITY_WARNING_MEDIUM;
  18238.     
  18239.     box.appendNotification(
  18240.                 prompt,
  18241.                 "su_prompt",
  18242.                 icon,
  18243.                 priority,
  18244.                 buttons);
  18245. }
  18246.  
  18247. function su_handle_prompt_click(prompt, button_name, detail)
  18248. {
  18249.     if (button_name == "accept")
  18250.     {
  18251.         su_verify_cookie_perms(false);
  18252.         var params = "";
  18253.         var loc = "sign_up.php"; 
  18254.         params = su_arp(params, "version", su_useragent);
  18255.         
  18256.         if (su_host.dist)
  18257.             loc = su_arp(loc, "dist", su_host.dist, true);
  18258.         
  18259.         if (su_ds.getValue("@facebook_user"))
  18260.             loc = su_arp(loc, "pre", "facebook", true);
  18261.         
  18262.         loc = su_arp(loc, "pre2", prompt, true);
  18263.         
  18264.         params = su_arp(params, "post_url", detail.post_url);
  18265.  
  18266.         su_set_server_location(
  18267.                     loc,
  18268.                     params,
  18269.                     detail.new_tab);
  18270.     }
  18271.     else if ((button_name == "decline") && (prompt == "prompt1"))
  18272.     {
  18273.         su_ds.setValue("@enable_prompt1", false);
  18274.     }
  18275.     else if ((button_name == "decline") && (prompt == "prompt2"))
  18276.     {
  18277.         su_ds.setValue("@enable_prompt2", false);
  18278.     }
  18279. }
  18280.  
  18281.  
  18282. // handles the window load event
  18283. function su_handle_window_load()
  18284. {
  18285.     if (! su_login_initialized)
  18286.     {
  18287.         setTimeout(su_handle_window_load, 1000);
  18288.         return;
  18289.     }
  18290.  
  18291.     if (stumbleid != 0)
  18292.     {
  18293.         if ((su_get_browser_window_count() == 1) && su_ds.getValue("$autologout"))
  18294.             su_logout_auth();
  18295.         else
  18296.             su_load_data1(false);
  18297.     }
  18298.  
  18299.     // we need to wait until the gui is rendered before we do most things
  18300.     setTimeout("su_gui_render()", 100);
  18301.  
  18302.     // Initialize photoblog context menu
  18303.     var menu = su_get_element("contentAreaContextMenu");
  18304.     menu.addEventListener("popupshowing", su_photoBlogContext, false); 
  18305. }
  18306.  
  18307. // handles the window unload event
  18308. function su_handle_window_unload()
  18309. {
  18310.     try {
  18311.     // To avoid a memory leak, this block needs to run per XUL window.
  18312.     // -- JW
  18313.     var observer_service = su_get_service(
  18314.                 "@mozilla.org/observer-service;1",
  18315.                 "nsIObserverService");
  18316.  
  18317.     observer_service.removeObserver(su_http_observer, "http-on-modify-request");
  18318.     observer_service.removeObserver(su_http_observer, "http-on-examine-response");
  18319.     observer_service.removeObserver(su_host_observer, "em-action-requested");
  18320.     observer_service.removeObserver(su_event_observer, "su_login");
  18321.     observer_service.removeObserver(su_event_observer, "su_logout");
  18322.     observer_service.removeObserver(su_event_observer, "su_change-password");
  18323.     observer_service.removeObserver(su_event_observer, "su_configure-toolbar");
  18324.     observer_service.removeObserver(su_event_observer, "su_referral-menu-dirty");
  18325.     observer_service.removeObserver(su_event_observer, "su_update-referral-menu");
  18326.     observer_service.removeObserver(su_event_observer, "su_dyn-channels-dirty");
  18327.     observer_service.removeObserver(su_event_observer, "su_update-dyn-channels");
  18328.     observer_service.removeObserver(su_event_observer, "su_refresh-category-selector");
  18329.     observer_service.removeObserver(su_event_observer, "su_schedule-remove-data");
  18330.     observer_service.removeObserver(su_event_observer, "su_message-button-click");
  18331.  
  18332.     var processed_ids = new Object();
  18333.     while (su_persist_queue.length)
  18334.     {
  18335.         // Doing document.persist can break the urlbar, so we do it upon
  18336.         // window close (ref: Firefox 2RC1). -- JW
  18337.         var id = su_persist_queue.pop();
  18338.         if (processed_ids[id])
  18339.             continue;
  18340.         
  18341.         processed_ids[id] = true;
  18342.  
  18343.         document.persist(id, "currentset");
  18344.     }
  18345.     
  18346.     if (su_get_browser_window_count() == 0)
  18347.         su_handle_last_browser_window_unload()
  18348.     
  18349.     } catch (e) {}
  18350. }
  18351.  
  18352. function su_handle_last_browser_window_unload()
  18353. {
  18354.     var i;
  18355.     if (su_ds.getValue("@clear_favicons"))
  18356.     {
  18357.         su_ds.setValue("@clear_favicons", false);
  18358.         var channels = su_ds.getThruDomainChannels(false);
  18359.         
  18360.         if (channels)
  18361.         {
  18362.             for (i = 0; i < channels.length; i++)
  18363.             {
  18364.                 su_ds.deleteResource(
  18365.                             "favicons",
  18366.                             su_get_channel_id(channels[i].domain) + ".ico");
  18367.             }
  18368.         }
  18369.     }
  18370.  
  18371.     if (su_is_uninstall_scheduled())
  18372.     {
  18373.         su_remove_searchplugin();
  18374.     }
  18375.     else if(!su_remove_data_scheduled)
  18376.     {
  18377.         var ids = su_ds.getValue("@id_list").split(":");
  18378.  
  18379.         for (i = 0; i < ids.length; i++)
  18380.         {
  18381.             if (ids[i] == "")
  18382.                 continue;
  18383.             
  18384.             stumbleid = ids[i];
  18385.             
  18386.             if (su_ds.getUserPrefValue(ids[i], "$search_clear_queries"))
  18387.             {
  18388.                 // If they've elected to clear queries, remove them.
  18389.                 su_queries = new Array();
  18390.                 su_store_queries();
  18391.             }
  18392.         }
  18393.         if (su_preference_dialog)
  18394.             su_preference_dialog.cancelDialog();
  18395.  
  18396.         if ((stumbleid != 0) &&    su_ds.getValue("$autologout"))
  18397.             su_logout();
  18398.         
  18399.         su_ds.flushPrefs();
  18400.     }
  18401.     
  18402.     if (su_remove_data_scheduled)
  18403.         su_remove_data();
  18404. }
  18405.  
  18406. // used by the window unload listener to determine whether the 
  18407. // extension has been scheduled to be uninstalled
  18408. function su_is_uninstall_scheduled()
  18409. {
  18410.     var root;
  18411.     if (su_uninstall_scheduled)
  18412.     {
  18413.         // In Firefox 1.5+, we use the su_uninstall_observer to detect a
  18414.         // scheduled uninstallation. -- JW
  18415.         return true;
  18416.     }
  18417.     else
  18418.     {
  18419.         try {
  18420.             root = su_get_rdf_resource("urn:mozilla:extension:root");
  18421.         }
  18422.         catch (e) {
  18423.             // This datasource has been renamed in Firefox 1.5+ and no
  18424.             // longer features the toBeUninstalled arcs. -- JW
  18425.             return false;
  18426.         }
  18427.     }
  18428.     
  18429.     // [kudos:] This is derived from the FirefoxView extension by Alex
  18430.     // Sirota. -- JW
  18431.     var container = su_get_service(
  18432.                 "@mozilla.org/rdf/container;1",
  18433.                 "nsIRDFContainer");
  18434.     var extension_ds = su_get_service(
  18435.                 "@mozilla.org/extensions/manager;1",
  18436.                 "nsIExtensionManager")
  18437.                 .datasource;
  18438.  
  18439.     try {
  18440.         container.Init(extension_ds, root);
  18441.     }
  18442.     catch (e) {
  18443.         return false;
  18444.     }
  18445.  
  18446.     var found = false;
  18447.     var elements = container.GetElements();
  18448.     while (elements.hasMoreElements())
  18449.     {
  18450.         var element = elements.getNext();
  18451.  
  18452.         var name = su_get_rdf_arc_literal(
  18453.                     extension_ds,
  18454.                     element,
  18455.                     "http://www.mozilla.org/2004/em-rdf#name"); 
  18456.  
  18457.         var to_be_uninstalled = su_get_rdf_arc_literal(
  18458.                     extension_ds,
  18459.                     element,
  18460.                     "http://www.mozilla.org/2004/em-rdf#toBeUninstalled");
  18461.  
  18462.         if ((to_be_uninstalled == "true") && (name == "StumbleUpon"))
  18463.             found = true;
  18464.     } 
  18465.     return found;
  18466. }
  18467.  
  18468. // if the extension is scheduled to be uninstalled, the window unload
  18469. // listener calls this routine to uninstall the search plugin
  18470. function su_remove_searchplugin()
  18471. {
  18472.     // [kudos:] This is derived from the SearchPluginHacks extension by
  18473.     // Alex Sirota. -- JW
  18474.  
  18475.     var i;
  18476.     var searchbar = su_get_element('searchbar');
  18477.     
  18478.     if (! searchbar)
  18479.         return;
  18480.  
  18481.     var searchbar_popup = document.getAnonymousElementByAttribute(
  18482.                 searchbar,
  18483.                 'anonid',
  18484.                 'searchbar-popup');
  18485.     var menuitems = searchbar_popup.getElementsByTagName("menuitem");
  18486.     
  18487.     var menuitem = null;
  18488.     
  18489.     for (i = 0; i < menuitems.length; i++)
  18490.     {
  18491.         if (menuitems[i].label == "StumbleUpon")
  18492.         {
  18493.             menuitem = menuitems[i];
  18494.             break;
  18495.         }
  18496.     }
  18497.     
  18498.     if (! menuitem)
  18499.         return;
  18500.  
  18501.     var plugin_uri = unescape(menuitem.value);
  18502.     var plugin_path;
  18503.     if (plugin_uri.indexOf("engine://") == 0)
  18504.         plugin_path = plugin_uri.substr(9);
  18505.     else
  18506.         su_log_error("SEARCHPLUGIN URI FORMAT ERROR", plugin_uri);
  18507.  
  18508.     var image_uri = unescape(menuitem.getAttribute('src'));
  18509.     var image_path;
  18510.     if (image_uri.indexOf("file:///") == 0)
  18511.     {
  18512.         var handler = su_create_instance(
  18513.                     "@mozilla.org/network/protocol;1?name=file",
  18514.                     "nsIFileProtocolHandler");
  18515.         image_path = handler.getFileFromURLSpec(image_uri).path;
  18516.     }
  18517.     else
  18518.     {
  18519.         su_log_error("SEARCHPLUGIN IMAGE URI FORMAT ERROR", image_uri);
  18520.     }
  18521.  
  18522.     try {
  18523.         su_ds.deleteFile(su_ds.getFileFromPath(plugin_path));
  18524.         su_ds.deleteFile(su_ds.getFileFromPath(image_path));
  18525.     } catch (e) {}
  18526.  
  18527.     try {
  18528.         if (typeof(searchbar_popup.hidePopup) == "function")
  18529.             searchbar_popup.hidePopup();
  18530.         menuitem.parentNode.removeChild(menuitem);
  18531.     } catch (e) {}
  18532. }
  18533.  
  18534. // handles the window click event
  18535. function su_handle_window_mousedown(event)
  18536. {
  18537.     if (! su_has_searchbox)
  18538.         return true;
  18539.     //    su_recent_platform_ctrl_key_state = (su_host.mac) ? event.metaKey : event.ctrlKey;
  18540.  
  18541.     if (! event.target.id)
  18542.         return;
  18543.     
  18544.     switch (event.target.id)
  18545.     {
  18546.         case "su_searchbox":
  18547.             su_keep_searchbox_focus = true;
  18548.             break;
  18549.         case "su_stumble":
  18550.         case "su_category":
  18551.         case "su_thumbup":
  18552.         case "su_thumbdown":
  18553.         case "su_website_info":
  18554.         case "su_tag":
  18555.         case "su_tag2":
  18556.             break;
  18557.         default:
  18558.             su_keep_searchbox_focus = false;
  18559.             break;
  18560.     }
  18561.     return true;
  18562. }
  18563.  
  18564. // handles the window focus event
  18565. function su_handle_window_focus(event)
  18566. {
  18567.     if (! su_has_searchbox)
  18568.         return true;
  18569.  
  18570.     if (su_keep_searchbox_focus && event.target.location && 
  18571.                 (event.target.location.href == "chrome://browser/content/browser.xul"))
  18572.     {
  18573.         setTimeout(su_restore_searchbox_focus, 100);
  18574.     }
  18575.     else if (su_keep_searchbox_focus && event.target.id && 
  18576.                 (event.target.id == "content"))
  18577.     {
  18578.         setTimeout(su_restore_searchbox_focus, 100);
  18579.     }
  18580. }
  18581.  
  18582. // restores the searchbox
  18583. function su_restore_searchbox_focus()
  18584. {
  18585.     if (su_keep_searchbox_focus)
  18586.     {
  18587.         var searchbox = su_get_element("su_searchbox");
  18588.         if (! (searchbox.hasAttribute("focused") && (searchbox.getAttribute("focused") == "true")))
  18589.             searchbox.focus();
  18590.     }
  18591. }
  18592.  
  18593. // handles the window keypress event; see also handle_window_keyup
  18594. function su_handle_window_keypress(event)
  18595. {
  18596. //    su_recent_platform_ctrl_key_state = (su_host.mac) ? event.metaKey : event.ctrlKey;
  18597.     
  18598.   var str = "";
  18599.  
  18600.     if (event.altKey)   str += "Alt+";
  18601.     if (event.ctrlKey)  str += "Ctrl+";
  18602.     if (event.metaKey)  str += "Command+";
  18603.     if (event.shiftKey) str += "Shift+";
  18604.  
  18605.     su_recent_keypress_modifiers = str;
  18606.  
  18607.     return true;
  18608. }
  18609.  
  18610. // handles the window keyup event using commands defined by 
  18611. // refresh_keybindings(); note that we need both a keypress listener
  18612. // and a keyup listener because the former gives us modifiers and the
  18613. // latter gives us keyCodes that distinquish between the numeric
  18614. // keypad w/ numlock on and the number row
  18615. function su_handle_window_keyup(event)
  18616. {
  18617.     var keyid;
  18618.     if (event.charCode)
  18619.         keyid = su_keyids_by_eventkeycode[event.charCode];
  18620.     else
  18621.           keyid = su_keyids_by_eventkeycode[event.keyCode];
  18622.  
  18623.     var keyspec = su_recent_keypress_modifiers + keyid;
  18624.     
  18625.     if (su_commands_by_keyspec[keyspec])
  18626.         su_commands_by_keyspec[keyspec].doCommand();
  18627.  
  18628.     return true;
  18629. }
  18630.  
  18631. function su_move_to_bookmark_bar()
  18632. {
  18633.     su_ds.setValue("@toolbar-position", "PersonalToolbar");
  18634.     su_ds.setValue("@position-group", "first");
  18635.     
  18636.     su_move_toolbar(true, 9);
  18637. }
  18638.  
  18639. // called by the global configure-toolbar event and during init to
  18640. // move the top-level toolbar elements
  18641. function su_move_toolbar(force, from)
  18642. {
  18643.     var toolbar_position = su_ds.getValue("@toolbar-position");
  18644.     var position_group = su_ds.getValue("@position-group");
  18645.     var toolbar = su_get_element(toolbar_position);
  18646.     var toolbaritem;
  18647.     var new_parent;
  18648.     var popup;
  18649.     if (! toolbar)
  18650.     {
  18651.         toolbar_position = "stumbleupon";
  18652.         position_group = "first";
  18653.         su_ds.setValue("@toolbar-position", toolbar_position);
  18654.         su_ds.setValue("@position-group", position_group);
  18655.         toolbar = su_get_element(toolbar_position);
  18656.         su_ds.flushPrefs();
  18657.     }
  18658.     
  18659.     if (force && (toolbar.tagName == "toolbar") && 
  18660.                 window.BrowserCustomizeToolbar && 
  18661.                 ((position_group == "first") || (position_group == "last")))
  18662.     {
  18663.         var splitter = su_get_element("su_right-justify-splitter");
  18664.         if (splitter)
  18665.             splitter.collapsed = true;
  18666.     
  18667.         // If we don't hide the popup, the menu gets munged if we move the
  18668.         // toolbar somewhere else.
  18669.         popup = su_get_element("su_stumble_popup");
  18670.         if (typeof(popup.hidePopup) == "function")
  18671.             popup.hidePopup();
  18672.         if (su_overflow_popup_open)
  18673.         {
  18674.             popup = su_get_element("su_overflow_popup"); 
  18675.             if (typeof(popup.hidePopup) == "function")
  18676.                 popup.hidePopup();
  18677.         }
  18678.         new_parent = su_get_element("su_container");
  18679.         new_parent.hidden = true;
  18680. //        su_dp("moving to hbox");
  18681.         su_move_toolbar_elements(new_parent, null, 1);
  18682.         
  18683.         var toolbars = document.getElementsByTagName("toolbar");
  18684.         var target_index = -1;
  18685.         var prev_index = -1;
  18686.         var i;
  18687.  
  18688.         // First, find the toolbar locations
  18689.         for (i = 0; i < toolbars.length; i++)
  18690.         {
  18691.             if(su_is_item_in_toolbox(false, "su_toolbaritem", toolbars[i]))
  18692.             {
  18693.                 prev_index = i;
  18694.                 if(target_index != -1) break;
  18695.             }
  18696.  
  18697.             if (! toolbars[i].hasAttribute("customizable"))
  18698.                 continue;
  18699.             
  18700.             if (toolbars[i].getAttribute("customizable").toLowerCase() != "true")
  18701.                 continue;
  18702.  
  18703.             if (toolbars[i].id == toolbar_position)
  18704.             {
  18705.                 target_index = i;
  18706.                 if(prev_index != -1) break;
  18707.             }
  18708.         }
  18709.  
  18710.         if(target_index != -1)
  18711.         {
  18712.             // Add it to the new
  18713.             su_place_toolbaritem(toolbars[target_index], position_group);
  18714.             // Remove it from the old
  18715.             if(target_index != prev_index)
  18716.             {
  18717.                 try {
  18718.                     su_is_item_in_toolbox(true, "su_toolbaritem", toolbars[prev_index]);
  18719.                 } catch (e) {};
  18720.             }
  18721.         }
  18722.         
  18723.         if((target_index == -1)  && (toolbar_position != "status-bar"))
  18724.         {
  18725.             // If we didn't find a valid (customizable) toolbar parent, then force our
  18726.             // toolbar to the default location.
  18727.             toolbar_position = "stumbleupon";
  18728.             position_group = "first";
  18729.             su_ds.setValue("@toolbar-position", toolbar_position);
  18730.             su_ds.setValue("@position-group", position_group);
  18731.             toolbar = su_get_element(toolbar_position);
  18732.             su_place_toolbaritem(toolbar, position_group);
  18733.             su_ds.flushPrefs();
  18734.         }
  18735.     }
  18736.  
  18737.     toolbaritem = su_get_element("su_toolbaritem");
  18738.     
  18739.     var drop = false;
  18740.     var new_bar;
  18741.     if ((toolbar_position == "status-bar") || 
  18742.                 (toolbar_position == "yahoo-toolbar"))
  18743.     {
  18744.         new_parent = su_get_element(toolbar_position);
  18745.         new_bar = new_parent;
  18746.     }
  18747.     else if (toolbaritem)
  18748.     {
  18749.         new_bar = toolbaritem.parentNode;
  18750.         var drop = true;
  18751.         if (su_is_element_on_bar(false, "gtbToolbar", "su_toolbaritem"))
  18752.         {
  18753.             toolbar_position = "gtbToolbar";
  18754.             new_parent = su_get_element("gtbToolbar");
  18755. //            su_dp("toolbaritem is on gtbToolbar", new_parent.id);
  18756.             position_group = "first";
  18757.             
  18758.             if (toolbaritem.hasAttribute("flex"))
  18759.                 toolbaritem.removeAttribute("flex");
  18760.             
  18761.             toolbaritem.setAttribute("width", 0);
  18762.             su_ds.setValue("@toolbar-position", toolbar_position);
  18763.         }
  18764.         else
  18765.         {
  18766.             new_parent = su_get_element("su_toolbar_container");
  18767.             try {
  18768.                 position_group = "drop";
  18769.                 toolbar_position = su_get_parent_toolbar_id(new_parent);
  18770.             }
  18771.             catch (e) {
  18772.                 //!!! This is a failsafe case that gets hit by some seamonkey
  18773.                 //    1.1 and Firefox 2.0.0.2 users.
  18774.                 if ((toolbar_position == "stumbleupon") && (position_group == "first"))
  18775.                     su_log_error("MOVE ERROR1", e);
  18776.                 else
  18777.                     su_log_error("MOVE FAILSAFE1", e, toolbar_position, position_group);
  18778.                 toolbar_position = "stumbleupon";
  18779.                 position_group = "first";
  18780.                 new_parent = su_get_element("su_container");
  18781.                 new_bar = new_parent.parentNode;
  18782.                 new_parent.hidden = false;
  18783.             }
  18784.             su_ds.setValue("@toolbar-position", toolbar_position);
  18785.             su_ds.setValue("@position-group", position_group);
  18786.         }
  18787.     }
  18788.     else if (toolbar_position == "stumbleupon")
  18789.     {
  18790.         new_parent = su_get_element("su_container");
  18791.         position_group = "first";
  18792.         su_ds.setValue("@toolbar-position", toolbar_position);
  18793.         su_ds.setValue("@position-group", position_group);
  18794.         new_bar = new_parent.parentNode;
  18795.         new_parent.hidden = false;
  18796.     }
  18797.     else
  18798.     {
  18799. //        su_dp("no toolbaritem");
  18800.         new_parent = su_get_element(toolbar_position);
  18801.         new_bar = new_parent;
  18802.     }
  18803.  
  18804.     // If the selected toolbar is missing, use the default location.
  18805.     if (! new_parent)
  18806.     {
  18807. //        su_dp("no new parent");
  18808.         toolbar_position = "stumbleupon";
  18809.         position_group = "first";
  18810.         su_ds.setValue("@toolbar-position", toolbar_position);
  18811.         su_ds.setValue("@position-group", position_group);
  18812.         new_parent = su_get_element("su_container");
  18813.         new_bar = new_parent.parentNode;
  18814.         force = true;
  18815.     }
  18816.  
  18817.     // if force, then make sure the toolbar they are moving to is not hidden
  18818.     if (force)
  18819.     {
  18820.         new_bar.hidden = false;
  18821.         new_bar.collapsed = false;
  18822.     }
  18823.  
  18824.     var hidden_state = ! su_ds.getValue("@toolbar-visible");
  18825.  
  18826.     if (toolbar_position == "stumbleupon")
  18827.     {
  18828.         su_get_element("stumbleupon").collapsed = hidden_state;
  18829.     }
  18830.     else
  18831.     {
  18832.         su_get_element("stumbleupon").collapsed = true;
  18833.         if (hidden_state)
  18834.         {
  18835. //            su_dp("hidden");
  18836.             // To hide the toolbar elements, we move them to the collapsed
  18837.             // toolbar. -- JW
  18838.             if (toolbaritem)
  18839.             {
  18840.                 if (toolbaritem.hasAttribute("flex"))
  18841.                     toolbaritem.removeAttribute("flex");
  18842.                 
  18843.                 toolbaritem.setAttribute("width", 0);
  18844.             }
  18845.             toolbar_position = "stumbleupon";
  18846.             new_parent = su_get_element("su_container");
  18847.         }
  18848.     }
  18849.     
  18850.     var old_parent = su_get_element("su_splitter_first_flexbox").parentNode;
  18851.     
  18852.     
  18853.     if ((toolbar_position == su_old_toolbar_position) && 
  18854.                 (position_group == su_old_toolbar_position_group) &&
  18855.                 (old_parent.id != "su_container"))
  18856.     {
  18857.         setTimeout(
  18858.                     function (win) {
  18859.                         win.su_cleanup_toolbox(true, false); },
  18860.                     0,
  18861.                     window);
  18862.     
  18863.         su_init_splitters();
  18864.         return;
  18865.     }
  18866.  
  18867. /*    
  18868.     if (toolbaritem)
  18869.     {
  18870.         if (toolbaritem.hasAttribute("width"))
  18871.             toolbaritem.removeAttribute("width");
  18872.         
  18873.         if (! toolbaritem.hasAttribute("flex"))
  18874.             toolbaritem.setAttribute("flex", 1);
  18875.     }
  18876. */
  18877.  
  18878.     su_bookmarks_sibling_loc = null;
  18879.     su_old_toolbar_position = toolbar_position;
  18880.     su_old_toolbar_position_group = position_group;
  18881.     
  18882.     su_moving_toolbar = true;
  18883.     
  18884.  
  18885.     // If we don't hide the popup, the menu gets munged if we move the
  18886.     // toolbar somewhere else.
  18887.     popup = su_get_element("su_stumble_popup");
  18888.     if (typeof(popup.hidePopup) == "function")
  18889.         popup.hidePopup();
  18890.     if (su_overflow_popup_open)
  18891.     {
  18892.         popup = su_get_element("su_overflow_popup"); 
  18893.         if (typeof(popup.hidePopup) == "function")
  18894.             popup.hidePopup();
  18895.     }
  18896.  
  18897.     if (toolbar_position == "stumbleupon")
  18898.     {
  18899.         su_toolbar_justification = "left";
  18900. //        su_dp("id", su_get_parent_toolbar_id(new_parent));
  18901.         su_move_toolbar_elements(new_parent, null, 2);
  18902.         
  18903.         // The following contains workarounds to fix the bug where the
  18904.         // toolbar appears 150px tall in old browsers (ref: Netscape 7.2,
  18905.         // XP and Firefox 1.0RC1, XP) -- JW
  18906.         if (new_parent.parentNode.boxObject.height > 100)
  18907.         {
  18908.             su_get_element("su_field").style.height = "32px";
  18909.             new_parent.style.height = "32px";
  18910.             new_parent.parentNode.style.height = "32px";
  18911.         }
  18912.         new_parent.hidden = false;
  18913.     }
  18914.     else if (toolbar_position == "gtbToolbar")
  18915.     {
  18916. //        su_dp("moving toolbar to gtbToolbar", new_parent.id);
  18917.         su_toolbar_justification = "left";
  18918.         hbox = document.createElement("hbox");
  18919.         hbox.setAttribute("id", "su_googlebar_container");
  18920.         new_parent.insertBefore(hbox, new_parent.firstChild);
  18921.         hbox.__defineSetter__("collapsed", function() {});
  18922.         new_parent = hbox;
  18923.         su_move_toolbar_elements(new_parent, null, 3);
  18924.     }
  18925.     else if ((position_group == "last") || (position_group == "drop"))
  18926.     {
  18927.         var sibling;
  18928.         if (position_group == "drop")
  18929.         {
  18930. //            su_dp("survey");
  18931.             try {
  18932.                 su_survey_toolbar_siblings(toolbaritem);
  18933.                 sibling = toolbaritem.previousSibling;
  18934.             }
  18935.             catch (e) {
  18936.                 if ((toolbar_position == "stumbleupon") && (position_group == "first"))
  18937.                     su_log_error("MOVE ERROR2", e);
  18938.                 else
  18939.                     su_log_error("MOVE FAILSAFE2", e, toolbar_position, position_group);
  18940.                 su_ds.setValue("@toolbar-position", "stumbleupon");
  18941.                 su_ds.setValue("@position-group", "first");
  18942.                 su_ds.setValue("@toolbar-visible", true);
  18943.             }    
  18944.         }
  18945.         else
  18946.         {
  18947.             sibling = new_parent.lastChild;
  18948.         }
  18949.         
  18950.         if ((toolbar_position == "PersonalToolbar") && 
  18951.                     (position_group == "last"))
  18952.             su_toolbar_justification = "right";
  18953.         else
  18954.             su_toolbar_justification = (su_test_previous_sibling_flexibility(sibling)) ? "right" : "left";
  18955.         
  18956. //        su_dp("justification", su_toolbar_justification);
  18957.         if (su_toolbar_justification == "left")
  18958.         {
  18959.             if (old_parent.id != "su_toolbar_container")
  18960.                 su_move_toolbar_elements(new_parent, null, 4);
  18961.         }
  18962.         else if (su_toolbar_justification == "right")
  18963.         {
  18964.             if ((old_parent.id == "su_toolbar_container") && 
  18965.                         (su_ds.getValue("@toolbar-position") != "status-bar"))
  18966.             {
  18967.                 if ((old_parent.parentNode.id != new_parent.id) && 
  18968.                             (position_group == "last"))
  18969.                     new_parent.appendChild(old_parent);
  18970.             }
  18971.             else
  18972.             {
  18973.                 if (position_group == "last")
  18974.                 {
  18975.                     var hbox;
  18976.                     if (su_ds.getValue("@toolbar-position") == "status-bar")
  18977.                         hbox = su_get_element("su_statusbar_container");
  18978.                     else
  18979.                         hbox = su_get_element("su_otherbar_container");
  18980.                     
  18981.                     if (! hbox)
  18982.                     {
  18983.                         hbox = document.createElement("hbox")
  18984.                         if (su_ds.getValue("@toolbar-position") == "status-bar")
  18985.                             hbox.setAttribute("id", "su_statusbar_container");
  18986.                         else
  18987.                             hbox.setAttribute("id", "su_otherbar_container");
  18988.                         hbox.setAttribute("flex", "1");
  18989.                     
  18990.                         new_parent.appendChild(hbox);
  18991.                     }
  18992.                     new_parent = hbox;
  18993.                 }
  18994.                 su_move_toolbar_elements(new_parent, null, 5);
  18995.                 
  18996.                 var outer_container = su_get_toolbar_outer_container();
  18997.                 var width = outer_container.boxObject.width;
  18998.                 width = su_ds.getPrefValue("@right-justify-width", width);
  18999.                 outer_container.setAttribute("width", width + "px");
  19000.                 if (outer_container.hasAttribute("flex"))
  19001.                     outer_container.removeAttribute("flex");
  19002.                 
  19003.                 if (su_bookmarks_sibling_loc)
  19004.                     setTimeout(su_move_toolbar_bookmarks, 1000, new_parent);
  19005.             }
  19006.         }
  19007.     }
  19008.     else
  19009.     {
  19010.         su_toolbar_justification = "left";
  19011.         su_move_toolbar_elements(new_parent, new_parent.firstChild, 6);
  19012.     }
  19013.     
  19014.     su_moving_toolbar = false;
  19015.  
  19016.     // change state of mozilla suite menuitem
  19017.     var menuitem = su_get_element("view_stumble_menuitem");
  19018.     if (menuitem)
  19019.     {
  19020.         if (hidden_state)
  19021.             menuitem.removeAttribute("checked");
  19022.         else
  19023.             menuitem.setAttribute("checked", "true");
  19024.     }
  19025.  
  19026.     setTimeout(
  19027.                 function (win) {
  19028.                     win.su_cleanup_toolbox(true, false); },
  19029.                 0,
  19030.                 window);
  19031.  
  19032.     su_init_splitters();
  19033. }
  19034.  
  19035. function su_verify_toolbar_move(from)
  19036. {
  19037.     if (su_get_element("su_stumble"))
  19038.         return;
  19039.     
  19040.     // If we can't find the stumble button, recover upon browser
  19041.     // restart.
  19042.     su_log_error(
  19043.                 "MOVE FAILSAFE4",
  19044.                 new Object(),
  19045.                 from,
  19046.                 su_ds.getValue("@toolbar-position"),
  19047.                 su_ds.getValue("@position-group"));
  19048.     
  19049.     su_ds.setValue("@toolbar-position", "stumbleupon");
  19050.     su_ds.setValue("@position-group", "first");
  19051.     
  19052.     if (from == 5)
  19053.     {
  19054.         setTimeout(alert, 50, 
  19055.                 "StumbleUpon cannot accommodate this new configuration.\n\n" +
  19056.                 "Please restart the browser to recover from this error.\n\n");
  19057.     }
  19058.     else if (from == 6)
  19059.     {
  19060.         setTimeout(alert, 50, 
  19061.                 "The specified toolbar movement cannot be completed.\n\n" +
  19062.                 "Please restart the browser to recover from this error.\n\n");
  19063.     }
  19064. }
  19065.  
  19066. function su_place_toolbaritem(toolbar, position_group)
  19067. {
  19068.     var currents;
  19069.     if ((typeof toolbar.currentSet) == "string")
  19070.         currents = toolbar.currentSet.split(",");
  19071.     else if (toolbar.hasAttribute("currentset"))
  19072.         currents = toolbar.getAttribute("currentset").split(",");
  19073.     else
  19074.         currents = new Array();
  19075.     
  19076.     if (position_group == "first")
  19077.     {
  19078.         if ((toolbar.id == "toolbar-menubar") && 
  19079.                     (currents[0] == "menubar-items"))
  19080.         {
  19081.             currents.splice(1, 0, "su_toolbaritem");
  19082.             var previous = su_get_element("menubar-items");
  19083.             if (previous)
  19084.             {
  19085.                 try {
  19086.                     toolbar.insertItem(
  19087.                                 "su_toolbaritem",
  19088.                                 previous.nextSibling,
  19089.                                 null,
  19090.                                 false);
  19091.                 } catch (e) { su_log("PLACE ERROR1", toolbar.id, position_group); }
  19092.             }
  19093.             else
  19094.             {
  19095.                 try {
  19096.                     toolbar.insertItem(
  19097.                                 "su_toolbaritem",
  19098.                                 toolbar.firstChild,
  19099.                                 null,
  19100.                                 true);
  19101.                 } catch (e) { su_log("PLACE ERROR2", toolbar.id, position_group); }
  19102.             }
  19103.         }
  19104.         else
  19105.         {
  19106.             currents.splice(0, 0, "su_toolbaritem");
  19107.             try {
  19108.                 toolbar.insertItem(
  19109.                             "su_toolbaritem",
  19110.                             toolbar.firstChild,
  19111.                             null,
  19112.                             true);
  19113.             } catch (e) { su_log("PLACE ERROR3", toolbar.id, position_group); }
  19114.         }
  19115.     }
  19116.     else if (position_group == "last")
  19117.     {
  19118.         currents.push("su_toolbaritem");
  19119.         
  19120.         toolbar.insertItem(
  19121.                     "su_toolbaritem",
  19122.                     null,
  19123.                     null,
  19124.                     false);
  19125.     }
  19126.     
  19127.     toolbar.setAttribute("currentset", currents.join(","));
  19128.     su_persist_queue.push(toolbar.id);
  19129. }
  19130.  
  19131. function su_move_toolbar_bookmarks(container)
  19132. {
  19133.     var width = su_ds.getValue("@right-justify-width");
  19134.     container.setAttribute("width", width + "px");
  19135.     if (container.hasAttribute("flex"))
  19136.         container.removeAttribute("flex");
  19137.  
  19138.     setTimeout(su_reflow_toolbar, 1000, 4);
  19139. }
  19140.  
  19141. function su_get_parent_toolbar_id(el)
  19142. {
  19143.     var toolbar = su_get_parent_toolbar(el);
  19144.     if (toolbar)
  19145.         return toolbar.id;
  19146.     else
  19147.         return null;
  19148. }
  19149.  
  19150. function su_get_parent_toolbar(el)
  19151. {
  19152.     var depth = 0;
  19153.     while ((el.tagName != "toolbar") && (el.tagName != "statusbar"))
  19154.     {
  19155.         depth++;
  19156.         if (depth == 1000)
  19157.         {
  19158.             break;
  19159.         }
  19160.         
  19161.         el = el.parentNode;
  19162.     }
  19163.     
  19164.     if (depth == 1000)
  19165.     {
  19166.         su_log_error("PARENT FIND", ((el && el.id) ? el.id : ("no id " + (typeof el))), su_ds.getValue("@toolbar-position"), su_ds.getValue("@position-group"));
  19167.         su_ds.setValue("@toolbar-position", "stumbleupon");
  19168.         su_ds.setValue("@position-group", "first");
  19169.         su_ds.setValue("@toolbar-visible", true);
  19170.         return null;
  19171.     }
  19172.     return el;
  19173. }
  19174.  
  19175. function su_survey_toolbar_siblings(outer_container)
  19176. {
  19177.     su_bookmarks_sibling_loc = null;
  19178.     if (! outer_container)
  19179.         return;
  19180.     var sibling = outer_container.parentNode.firstChild;
  19181.     var seen_container = false;
  19182.     while (sibling)
  19183.     {
  19184.         if (! sibling.id)
  19185.             continue;
  19186.         
  19187.         if (sibling == outer_container)
  19188.             seen_container = true;
  19189.         if (sibling.id == "personal-bookmarks")
  19190.         {
  19191.             su_bookmarks_sibling_loc = (seen_container) ? "right" : "left";
  19192.             break;
  19193.         }
  19194.         sibling = sibling.nextSibling;
  19195.     }
  19196. }
  19197.  
  19198. // used by move_toolbar() to determine whether any previous sibling
  19199. // of the toolbar is a flexible element; if one is, then the toolbar
  19200. // is right-justified
  19201. function su_test_previous_sibling_flexibility(previous_sibling)
  19202. {
  19203.     var sibling = previous_sibling;
  19204.     var regexp = new RegExp("^spring\\d+$");
  19205.     
  19206.     var found_flexible_element = false;
  19207.     while (sibling)
  19208.     {
  19209.         if (sibling.hasAttribute("flex") || (sibling.id && (sibling.id.search(regexp) == 0)))
  19210.         {
  19211.             found_flexible_element = true;
  19212.             break;
  19213.         }
  19214.         sibling = sibling.previousSibling;
  19215.     }
  19216.     return found_flexible_element;
  19217. }
  19218.  
  19219.  
  19220. // moves the top-level toolbar elements from
  19221. // su_splitter_first_flexbox through either su_site-box-count or
  19222. // su_overflow_menu to a new location subsequent to argument 
  19223. // target_next_sibling
  19224. function su_move_toolbar_elements(target_parent, target_next_sibling, from)
  19225. {
  19226.     try {
  19227. //    throw("t");
  19228.  
  19229.     var sibling = su_get_element("su_splitter_first_flexbox");
  19230.     var previous_sibling_id = "";
  19231.     var old_parent = sibling.parentNode;
  19232. //    su_dp("move elements", old_parent.id, target_parent.id, from);
  19233.     
  19234.     var depth = 0;
  19235.     
  19236.     while (previous_sibling_id != "su_overflow_menu")
  19237.     {
  19238.         depth++;
  19239.         if (depth == 1000)
  19240.         {
  19241.             break;
  19242.         }
  19243.         
  19244.         previous_sibling_id = sibling.id;
  19245.         var element = sibling;
  19246.         sibling = sibling.nextSibling;
  19247.         var new_element;
  19248.         if ((element.id == "su_stumble_menu") || (element.id =="su_category") ||
  19249.                     (element.id == "su_field") || (element.id == "su_referral_menu") ||
  19250.                     (element.id == "su_overflow_menu"))
  19251.         {
  19252.             new_element = element;
  19253.         }
  19254.         else
  19255.         {
  19256.             new_element = element.cloneNode(true);
  19257.             element.parentNode.removeChild(element);
  19258.         }
  19259.         
  19260.         if (target_next_sibling)
  19261.             target_parent.insertBefore(new_element, target_next_sibling);
  19262.         else
  19263.             target_parent.appendChild(new_element);
  19264.         
  19265.         if (new_element.id == "su_field")
  19266.         {
  19267.             var width = su_ds.getValue("@search-width");
  19268.             new_element.setAttribute("width", width + "px");
  19269.         }
  19270.     }
  19271.     
  19272.     if (depth == 1000)
  19273.     {
  19274.         su_log_error("MOVE LOOP", from, su_ds.getValue("@toolbar-position"), su_ds.getValue("@position-group"));
  19275.         su_ds.setValue("@toolbar-position", "stumbleupon");
  19276.         su_ds.setValue("@position-group", "first");
  19277.         su_ds.setValue("@toolbar-visible", true);
  19278.     }
  19279.     
  19280.     if ((old_parent.id == "su_statusbar_container") && 
  19281.                 (target_parent.id != "su_statusbar_container"))
  19282.         old_parent.parentNode.removeChild(old_parent);
  19283.     
  19284.     if ((old_parent.id == "su_googlebar_container") && 
  19285.                 (target_parent.id != "su_googlebar_container"))
  19286.         old_parent.parentNode.removeChild(old_parent);
  19287.     
  19288.     if ((old_parent.id == "su_otherbar_container") && 
  19289.                 (target_parent.id != "su_otherbar_container"))
  19290.         old_parent.parentNode.removeChild(old_parent);
  19291.     
  19292.     } catch (e) {
  19293.         su_log_error("MOVE TOOLBAR", e, from, su_ds.getValue("@toolbar-position"), su_ds.getValue("@position-group"));
  19294.         
  19295.         su_ds.setValue("@toolbar-position", "stumbleupon");
  19296.         su_ds.setValue("@position-group", "first");
  19297.         su_ds.setValue("@toolbar-visible", true);
  19298.     }
  19299. }
  19300.  
  19301. function su_refresh_toggle_button(force)
  19302. {
  19303.     if (! window.BrowserCustomizeToolbar)
  19304.         return;
  19305.     
  19306.     var visible = su_ds.getValue("@toolbar_toggle_visible");
  19307.     var found = false;
  19308.  
  19309.     found = su_is_item_in_toolbox((force && (! visible)), "su_toggle");
  19310.     
  19311.     if (! force)
  19312.         su_ds.setValue("@toolbar_toggle_visible", found);
  19313.  
  19314.     if (force && (! found) && visible)
  19315.         su_add_toggle_button();
  19316. }
  19317.  
  19318. function su_add_toggle_button()
  19319. {
  19320.     if (document.getElementById("su_toggle"))
  19321.         return;
  19322.     
  19323.     var urlbar = su_get_element("urlbar-container");
  19324.     
  19325.     var target = null;
  19326.     if (urlbar)
  19327.         target = urlbar.parentNode;
  19328.     
  19329.     if (target && target.collapsed)
  19330.         target = null;
  19331.     
  19332.     var preferred_target = (target) ? true : false;
  19333.     
  19334.     if (! target)
  19335.         target = su_get_element("nav-bar");
  19336.     
  19337.     if (target && target.collapsed)
  19338.         target = null;
  19339.     
  19340.     if (! target)
  19341.         target = su_get_element("toolbar-menubar");
  19342.     
  19343.     if (target && target.collapsed)
  19344.         target = null;
  19345.     
  19346.     if (target && target.hasAttribute("customizable") && 
  19347.                 (target.getAttribute("customizable").toLowerCase() == "true"))
  19348.     {
  19349.         var currents = target.currentSet.split(",");
  19350.         if (preferred_target)
  19351.         {
  19352.             var i;
  19353.             for (i = 0; i < currents.length; i++)
  19354.             {
  19355.                 if (currents[i] == "urlbar-container")
  19356.                 {
  19357.                     currents.splice(i, 0, "su_toggle");
  19358.                     break;
  19359.                 }
  19360.             }
  19361.             target.insertItem("su_toggle", urlbar, null, false);
  19362.         }
  19363.         else
  19364.         {
  19365.             currents.push("su_toggle");
  19366.             
  19367.             target.insertItem("su_toggle", null, null, false);
  19368.         }
  19369.         
  19370.         target.setAttribute("currentset", currents.join(","));
  19371.         su_persist_queue.push(target.id);
  19372.     }
  19373.     else
  19374.     {
  19375.         su_ds.setValue("@toolbar_toggle_visible", false);
  19376.     }
  19377. }
  19378.  
  19379. function su_is_item_in_toolbox(remove, id, opt_toolbar)
  19380. {
  19381.     var toolbars;
  19382.     if (opt_toolbar)
  19383.     {
  19384.         toolbars = new Array();
  19385.         toolbars.push(opt_toolbar);
  19386.     }
  19387.     else
  19388.     {
  19389.         toolbars = document.getElementsByTagName("toolbar");
  19390.     }
  19391.  
  19392.     var found = false;
  19393.     var i;
  19394.     for (i = 0; i < toolbars.length; i++)
  19395.     {
  19396.         var item = su_get_element(id);
  19397.         
  19398.         if (remove)
  19399.             su_is_element_on_bar(true, toolbars[i].id, id);
  19400.  
  19401.         if (! toolbars[i].hasAttribute("customizable"))
  19402.             continue;
  19403.         
  19404.         if (! toolbars[i].getAttribute("customizable").toLowerCase() == "true")
  19405.             continue;
  19406.         
  19407.         var currents;
  19408.         if ((typeof toolbars[i].currentSet) == "string")
  19409.             currents = toolbars[i].currentSet.split(",");
  19410.         else
  19411.             currents = new Array();
  19412.  
  19413.         var new_currents = new Array();
  19414.         while(currents.length)
  19415.         {
  19416.             if (currents[0] == id)
  19417.             {
  19418.                 found = true;
  19419.                 if (remove)
  19420.                     currents.shift();
  19421.                 else
  19422.                     new_currents.push(currents.shift());
  19423.             }
  19424.             else
  19425.             {
  19426.                 new_currents.push(currents.shift());
  19427.             }
  19428.         }
  19429.         
  19430.         var current_set = new_currents.join(",");
  19431.         
  19432.         var old_set;
  19433.         if (toolbars[i].hasAttribute("currentset"))
  19434.             old_set = toolbars[i].getAttribute("currentset");
  19435.         else
  19436.             old_set = "";
  19437.         
  19438.         toolbars[i].setAttribute("currentset", current_set);
  19439.         if (current_set != old_set)
  19440.             su_persist_queue.push(toolbars[i].id);
  19441.     }
  19442.     return found;
  19443. }
  19444.  
  19445. function su_is_element_on_bar(remove, toolbar_id, id)
  19446. {
  19447.     // This works around a browser bug where el.parentNode.id can report
  19448.     // the wrong id when parentNode is a toolbar (ref: Firefox 2.0rc1, 
  19449.     // Linux).  --  JW
  19450.     var toolbar = su_get_element(toolbar_id);
  19451.     
  19452.     if (! toolbar)
  19453.         return false;
  19454.     
  19455.     var found = false;
  19456.     var sibling = toolbar.firstChild;
  19457.     var count = 0;
  19458.     var el;
  19459.     while (sibling)
  19460.     {
  19461.         count++;
  19462.         if (count == 1000)
  19463.         {
  19464.             break;
  19465.         }
  19466.         el = sibling;
  19467.         sibling = sibling.nextSibling;
  19468.         if (el.id == id)
  19469.         {
  19470.             found = true;
  19471.             if (remove)
  19472.                 toolbar.removeChild(el);
  19473.         }
  19474.     }
  19475.     
  19476.     if (count == 1000)
  19477.         su_log_error("ON LOOP");
  19478.     
  19479.     return found;
  19480. }
  19481.  
  19482.  
  19483. // this is part of a hack that redefines behavior of the view->
  19484. // toolbars->StumbleUpon menuitem in Firefox-derived browsers
  19485. function su_replacement_onViewToolbarsPopupShowing(event)
  19486. {
  19487.     // During initialization, we make 
  19488.     // window.su_saved_onViewToolbarsPopupShowing point to the browser-
  19489.     // defined function window.onViewToolbarsPopupShowing (ref Firefox
  19490.     // 1.5).  Then we make window.onViewToolbarsPopupShowing point to
  19491.     // this function.  So this function runs when the browser invokes
  19492.     // window.onViewToolbarsPopupShowing(..).
  19493.     //
  19494.     // This function executes the original browser-defined routine 
  19495.     // before locating and modifying the StumbleUpon Toolbar menuitem. 
  19496.     // -- JW
  19497.     
  19498.     window.su_saved_onViewToolbarsPopupShowing(event);
  19499.     
  19500.     var sibling = event.target.firstChild;
  19501.     
  19502.     var found = false;
  19503.     while (sibling)
  19504.     {
  19505.         if (sibling.getAttribute("label").indexOf("StumbleUpon Toolbar") == 0)
  19506.         {
  19507.             found = true;
  19508.             break;
  19509.         }
  19510.         sibling = sibling.nextSibling;
  19511.     }
  19512.     
  19513.     if (found)
  19514.     {
  19515.         var menuitem = sibling;
  19516.         menuitem.setAttribute("checked", su_ds.getValue("@toolbar-visible"));
  19517.         menuitem.removeEventListener("command", onViewToolbarCommand, false);
  19518.         menuitem.addEventListener("command", su_handle_view_toolbar_command, false);
  19519.     }
  19520. }
  19521.  
  19522. function su_replacement_BrowserCustomizeToolbar()
  19523. {
  19524.     var toolbars = document.getElementsByTagName("toolbar");
  19525.     var i;
  19526.     var found = false;
  19527.     for (i = 0; i < toolbars.length; i++)
  19528.     {
  19529.         if (toolbars[i].hasAttribute("currentset"))
  19530.         {
  19531.             var currents = toolbars[i].getAttribute("currentset").split(",");
  19532.             var j;
  19533.             for (j = 0; j < currents.length; j++)
  19534.             {
  19535.                 if (currents[j] == "su_toolbaritem")
  19536.                 {
  19537.                     found = true;
  19538.                     break;
  19539.                 }
  19540.             }
  19541.         }
  19542.     }
  19543.     
  19544.     if (! found)
  19545.     {
  19546.         var item = su_get_element("su_toolbaritem");
  19547.         var toolbar = su_get_element("stumbleupon");
  19548.         toolbar.setAttribute("currentset", "su_toolbaritem");
  19549.         toolbar.insertItem("su_toolbaritem", null, null, true);
  19550.         su_persist_queue.push("stumbleupon");
  19551.     }
  19552.     
  19553.     setTimeout("su_replacement_BrowserCustomizeToolbar2();", 200);
  19554.  
  19555.     var position = su_ds.getValue("@toolbar-position"); 
  19556.     
  19557.     if ((position == "status-bar") || (position == "yahoo-toolbar"))
  19558.         return;
  19559.     
  19560.     
  19561.     var el = su_get_element("bookmarks-ptf");
  19562.     if (el)
  19563.         el.hidden = true;
  19564.  
  19565.     var new_parent = su_get_element("su_container");
  19566.     new_parent.hidden = true;
  19567.  
  19568.     var splitter = su_get_element("su_right-justify-splitter");
  19569.     if (splitter)
  19570.         splitter.collapsed = true;
  19571.  
  19572.     su_move_toolbar_elements(new_parent, null, 7);
  19573.     
  19574.     var needs_cleanup = false;
  19575.  
  19576.     var container = su_get_element("su_googlebar_container");
  19577.     if (container)
  19578.     {
  19579.         needs_cleanup = true;
  19580.         container.parentNode.removeChild(container);
  19581.     }
  19582.  
  19583.     var toolbaritem = su_get_element("su_toolbaritem");
  19584.     if (toolbaritem)
  19585.     {
  19586.         needs_cleanup = true;
  19587.         if (toolbaritem.hasAttribute("width"))
  19588.             toolbaritem.removeAttribute("width");
  19589.         
  19590.         if (toolbaritem.hasAttribute("flex"))
  19591.             toolbaritem.removeAttribute("flex");
  19592.     }
  19593.     
  19594.     if (needs_cleanup)
  19595.         su_cleanup_toolbox(true, true);
  19596. }
  19597.  
  19598. function su_replacement_BrowserCustomizeToolbar2()
  19599. {
  19600.     window.su_saved_BrowserCustomizeToolbar();
  19601.     
  19602.     var position = su_ds.getValue("@toolbar-position"); 
  19603.     if ((position == "status-bar") || (position == "yahoo-toolbar"))
  19604.     {
  19605.         su_get_element("stumbleupon").collapsed = true;
  19606.         su_get_element("su_toolbar_customize_label").value = "";
  19607.     }
  19608.     else
  19609.     {
  19610.         var shortcut = su_ds.getValue("$shortcut_toolbar");
  19611.         var label = "StumbleUpon Toolbar Items";
  19612.         if (shortcut != "")
  19613.         {
  19614.             label += " (" + 
  19615.                         su_get_display_keyspec(shortcut) + 
  19616.                         ")";
  19617.         }
  19618.         
  19619.         su_get_element("stumbleupon").collapsed = false;
  19620.         su_get_element("su_toolbar_customize_label").value = label;
  19621.     }
  19622. }
  19623.  
  19624. function su_replacement_BrowserToolboxCustomizeDone(aToolboxChanged)
  19625. {
  19626.     if (window.su_saved_BrowserToolboxCustomizeDone)
  19627.         window.su_saved_BrowserToolboxCustomizeDone(aToolboxChanged);
  19628.     
  19629.     su_refresh_toggle_button(false);
  19630.     
  19631.     var position = su_ds.getValue("@toolbar-position");
  19632.     if ((position == "status-bar") || (position == "yahoo-toolbar"))
  19633.         return;
  19634.     
  19635.     var el = su_get_element("bookmarks-ptf");
  19636.     if (el)
  19637.         el.hidden = false;
  19638.     
  19639.     var outer_container = su_get_element("su_toolbaritem");
  19640.     if (outer_container)
  19641.     {
  19642.         setTimeout(su_replacement_BrowserToolboxCustomizeDone2, 0);
  19643.     }
  19644.     else
  19645.     {
  19646.         su_get_element("stumbleupon").collapsed = true;
  19647.         var toolbar = su_get_element("stumbleupon");
  19648.         var currents = toolbar.currentSet.split(",");
  19649.         currents.push("su_toolbaritem");
  19650.         toolbar.setAttribute("currentset", currents.join(","));
  19651.         toolbar.insertItem("su_toolbaritem", null, null, true); 
  19652.         su_ds.setValue("@toolbar-visible", false);
  19653.         su_persist_queue.push("stumbleupon");
  19654.     }
  19655.     if (su_customize_invoked_from_preference_dialog)
  19656.     {
  19657.         su_customize_invoked_from_preference_dialog = false;
  19658.         setTimeout(su_preferences, 1000);
  19659.     }
  19660.  
  19661.     su_get_element("su_toolbar_customize_label").value = "";
  19662. }
  19663.  
  19664. function su_replacement_BrowserToolboxCustomizeDone2()
  19665. {
  19666.     su_move_toolbar(false, 5)
  19667.     su_reflow_toolbar(5);
  19668.     setTimeout(su_verify_toolbar_move, 0, 5);
  19669. }
  19670.  
  19671. function su_replacement_foxytunesSetFoxyTunesPosition()
  19672. {
  19673.     try {
  19674.         su_saved_foxytunesSetFoxyTunesPosition();
  19675.     } catch (e) {}
  19676.     setTimeout(su_replacement_BrowserToolboxCustomizeDone2, 200);
  19677. }
  19678.  
  19679. function su_is_toolbar_shared()
  19680. {
  19681.     var toolbar = su_get_element("stumbleupon");
  19682.     var sibling = toolbar.firstChild;
  19683.     var count = 0;
  19684.     var el;
  19685.     while (sibling)
  19686.     {
  19687.         count++;
  19688.         if (count == 1000)
  19689.             break;
  19690.         
  19691.         el = sibling;
  19692.         sibling = sibling.nextSibling;
  19693.         switch (el.id)
  19694.         {
  19695.             case "su_toolbaritem":
  19696.             case "stringbundleset":
  19697.             case "bundle_stumble":
  19698.             case "su_commandset":
  19699.             case "su_keyset":
  19700.             case "su_container":
  19701.             case "su_render":
  19702.                 break;
  19703.             default:
  19704.                 return true;
  19705.         }
  19706.     }
  19707.     
  19708.     return false;
  19709. }
  19710.  
  19711. function su_prevent_toolbar_sharing()
  19712. {
  19713.     if (! window.BrowserCustomizeToolbar)
  19714.         return;
  19715.     
  19716.     var toolbar = su_get_element("stumbleupon");
  19717.     var currents = toolbar.currentSet.split(",");
  19718.     var new_currents = new Array();
  19719.     var i;
  19720.     var modified = false;
  19721.     var el;
  19722.     for (i = 0; i < currents.length; i++)
  19723.     {
  19724.         switch (currents[i])
  19725.         {
  19726.             case "__empty":
  19727.             case "su_toolbaritem":
  19728.                 new_currents.push(currents[i]);
  19729.                 break;
  19730.             default:
  19731.                 modified = true;
  19732.                 break;
  19733.         }
  19734.     }
  19735.     
  19736.     var sibling = toolbar.firstChild;
  19737.     var count = 0;
  19738.     while (sibling)
  19739.     {
  19740.         count++;
  19741.         if (count == 1000)
  19742.         {
  19743.             break;
  19744.         }
  19745.         el = sibling;
  19746.         sibling = sibling.nextSibling;
  19747.         switch (el.id)
  19748.         {
  19749.             case "su_toolbaritem":
  19750.             case "stringbundleset":
  19751.             case "bundle_stumble":
  19752.             case "su_commandset":
  19753.             case "su_keyset":
  19754.             case "su_container":
  19755.             case "su_render":
  19756.                 break;
  19757.             default:
  19758.                 toolbar.removeChild(el);
  19759.         }
  19760.     }
  19761.     
  19762.     if (count == 1000)
  19763.         su_log_error("SHARING LOOP");
  19764.     
  19765.     if (modified)
  19766.     {
  19767.         var new_parent = su_get_element("stumbleupon-hbox");
  19768.         new_parent.hidden = true;
  19769.         su_move_toolbar_elements(new_parent, null, 8);
  19770.  
  19771.         toolbar.setAttribute("currentset", currents.join(","));
  19772.         su_persist_queue.push("stumbleupon");
  19773.         setTimeout("su_move_toolbar(false, 3);", 0);
  19774.         setTimeout(su_reflow_toolbar, 0, 6);
  19775.     }
  19776. }
  19777.  
  19778. function su_customize_toolbox()
  19779. {
  19780.     su_customize_invoked_from_preference_dialog = true;
  19781.     document.getElementById("cmd_CustomizeToolbars").doCommand();
  19782. }
  19783.  
  19784. // forwards the view->toolbars menuitem command event in Firefox-
  19785. // derived browsers
  19786. function su_handle_view_toolbar_command(event)
  19787. {
  19788.     setTimeout("su_toggle_toolbar();", 0);
  19789. }
  19790.  
  19791. // ultimately called by the view->toolbars menuitem in Firefox-
  19792. // derived browsers
  19793. function su_toggle_toolbar()
  19794. {
  19795.     su_toggling_toolbar = true;
  19796.  
  19797.     var toolbar_position = su_ds.getValue("@toolbar-position");
  19798.  
  19799.     var new_visible_state;
  19800.     if (toolbar_position == "stumbleupon")
  19801.         new_visible_state = su_get_element("stumbleupon").collapsed;
  19802.     else
  19803.         new_visible_state = ! su_ds.getValue("@toolbar-visible");
  19804.  
  19805.     su_ds.setValue("@toolbar-visible", new_visible_state);
  19806.     
  19807.     su_move_toolbar(false, 4);
  19808.  
  19809.     su_toggling_toolbar = false;
  19810.  
  19811.     if (new_visible_state)
  19812.         su_reflow_toolbar(7);
  19813.  
  19814. /*
  19815.     if (su_new_install && (! su_ds.getValue("@shown_toolbar")))
  19816.     {
  19817.         su_ds.setValue("@shown_toolbar", true);
  19818.         stumble(0);
  19819.     }
  19820. */
  19821.  
  19822.     su_ds.flushPrefs();
  19823. }
  19824.  
  19825. // handles the mousedown event for the splitter to the right of the 
  19826. // search box
  19827. function su_handle_splitter_search_right_mousedown(event)
  19828. {
  19829.     su_moving_splitter = true;
  19830.     var outer_container = su_get_element("su_toolbaritem");
  19831.     if (outer_container || (su_toolbar_justification == "right"))
  19832.         su_shorten_toolbar_to_element("su_splitter_search_right");
  19833.     su_set_toolbar_element_widths(su_get_element("su_stumble"));
  19834.  
  19835.     return true;
  19836. }
  19837.  
  19838. // handles the mouseup event for the splitter to the right of the 
  19839. // search box
  19840. function su_handle_splitter_search_right_mouseup(event)
  19841. {
  19842.     setTimeout('su_remove_toolbar_element_widths(su_get_element("su_stumble"))', 0);        
  19843.     su_moving_splitter = false;
  19844.     if (su_get_element("su_field").boxObject.width > 400)
  19845.         setTimeout('su_get_element("su_field").setAttribute("width", "400px")');
  19846.  
  19847.     setTimeout("su_refresh_splitters(false)", 0);
  19848.     return true;
  19849. }
  19850.  
  19851. function su_get_toolbar_outer_container()
  19852. {
  19853.     var position = su_ds.getValue("@toolbar-position");
  19854.     var container;
  19855.     if ((position == "status-bar") && 
  19856.                 (su_ds.getValue("@position-group") == "last"))
  19857.     {
  19858.         container = su_get_element("su_statusbar_container");
  19859.     }
  19860.     else if (su_ds.getValue("@position-group") == "last")
  19861.     {
  19862.         container = su_get_element("su_otherbar_container");
  19863.     }
  19864.     else if (position == "gtbToolbar")
  19865.     {
  19866.         container = su_get_element("su_googlebar_container");
  19867.     }
  19868.     
  19869.     if (! container)
  19870.     {
  19871.         container = su_get_element("su_stumble").parentNode;
  19872.     }
  19873.     
  19874.     if (container.id == "su_toolbar_container")
  19875.     {
  19876.         container = su_get_element("su_toolbaritem");
  19877.     }
  19878.     return container;
  19879. }
  19880.  
  19881. // handles the mouseup event for the dynamic splitter that's created
  19882. // when the toolbar is right-justified
  19883. function su_handle_right_justify_splitter_mousedown(event)
  19884. {
  19885.     su_moving_splitter = true;
  19886.     
  19887.     su_shorten_toolbar_to_element("su_thumbdown");
  19888.     
  19889.     su_set_toolbar_element_widths(su_get_toolbar_outer_container());
  19890.     
  19891.     return true;
  19892. }
  19893.  
  19894. // handles the mousedown event for the dynamic splitter that's
  19895. // created when the toolbar is right-justified
  19896. function su_handle_right_justify_splitter_mouseup(event)
  19897. {
  19898.     var hbox = su_get_toolbar_outer_container();
  19899.  
  19900.     su_ds.setValue("@right-justify-width", hbox.boxObject.width);
  19901.     
  19902.     setTimeout('su_remove_toolbar_element_widths(su_get_element("' + 
  19903.                 hbox.id + '"))', 0);        
  19904.     su_moving_splitter = false;
  19905.     setTimeout("su_refresh_splitters(false)", 0);
  19906.     
  19907.     return true;
  19908. }
  19909.  
  19910. // used by splitter mousedown listeners to set temporary minwidths 
  19911. // for adjacent elements
  19912. function su_set_toolbar_element_widths(sibling)
  19913. {
  19914.     sibling = sibling.parentNode.firstChild;
  19915.  
  19916.     while (sibling != null)
  19917.     {
  19918.         if (sibling.id == "personal-bookmarks")
  19919.         {
  19920.             var el = su_get_element("bookmarks-stack");
  19921.             if (el)
  19922.                 el.hidden = true;
  19923.         }
  19924.         else if (sibling.id && (sibling.id.indexOf("spring") != 0) && 
  19925.                     (sibling.id != "su_splitter_first_flexbox") &&
  19926.                     (sibling.id != "su_field") &&
  19927.                     (sibling.id != "su_toolbar_container") &&
  19928.                     (sibling.id != "su_toolbaritem") &&
  19929.                     (sibling.id != "su_statusbar_container") &&
  19930.                     (sibling.id != "su_otherbar_container") &&
  19931.                     (sibling.id != "su_googlebar_container") &&
  19932.                     (sibling.tagName != "tooltip") &&
  19933.                     (! sibling.hasAttribute("flex")))
  19934.         {
  19935.             if (sibling.hasAttribute("minwidth"))
  19936.                 sibling.setAttribute("su_savedminwidth", sibling.getAttribute("minwidth"));
  19937.  
  19938.             if (sibling.hasAttribute("width"))
  19939.                 sibling.setAttribute("su_hadwidth", "true");
  19940.             
  19941.             sibling.setAttribute("minwidth", sibling.boxObject.width + "px");
  19942.         }
  19943.         
  19944.         sibling = sibling.nextSibling;
  19945.     }
  19946. }
  19947.  
  19948. // used by splitter mouseup listeners to remove the temporary 
  19949. // minwidths set by set_toolbar_element_widths
  19950. function su_remove_toolbar_element_widths(sibling)
  19951. {
  19952.     sibling = sibling.parentNode.firstChild;
  19953.  
  19954.     while (sibling != null)
  19955.     {
  19956.         if (sibling.hasAttribute("su_savedminwidth"))
  19957.             sibling.setAttribute("minwidth", sibling.getAttribute("su_savedminwidth"));
  19958.         else
  19959.             sibling.removeAttribute("minwidth");
  19960.  
  19961.         if (sibling.id == "personal-bookmarks")
  19962.         {
  19963.             var el = su_get_element("bookmarks-stack");
  19964.             if (el)
  19965.             {
  19966.                 el.hidden = false;
  19967.             }
  19968.         }
  19969.         else if ((sibling.id != "su_splitter_first_flexbox") && 
  19970.                     (sibling.id != "su_field") &&
  19971.                     (sibling.id != "su_toolbar_container") && 
  19972.                     (sibling.id != "su_toolbaritem") &&
  19973.                     (sibling.id != "su_statusbar_container") &&
  19974.                     (sibling.id != "su_otherbar_container") &&
  19975.                     (sibling.id != "su_googlebar_container") &&
  19976.                     (sibling.tagName != "tooltip"))
  19977.         {
  19978.             if (sibling.hasAttribute("su_hadwidth"))
  19979.                 sibling.removeAttribute("su_hadwidth");
  19980.             else
  19981.                 sibling.removeAttribute("width");
  19982.         }
  19983.         sibling = sibling.nextSibling;
  19984.     }
  19985. }
  19986.  
  19987. function su_shorten_toolbar_to_element(stop_id)
  19988. {
  19989.     var popup = su_get_element("su_overflow_popup");
  19990.     var i;
  19991.     var item;
  19992.     for (i = 0; i < popup.childNodes.length; i++)
  19993.     {
  19994.         item = popup.childNodes[i];
  19995.         if (item.id && (item.id == stop_id))
  19996.             return;
  19997.     }
  19998.     
  19999.     var container = su_get_element("su_stumble").parentNode;
  20000.     
  20001.     var menuified_one = false;
  20002.     for (i = container.childNodes.length - 2; i >= 0; i--)
  20003.     {
  20004.         item = container.childNodes[i];
  20005.         if (item.id && (item.id == stop_id))
  20006.             break;
  20007.         su_menuify_toolbar_element(item);
  20008.         menuified_one = true;
  20009.     }
  20010.     if (menuified_one)
  20011.     {
  20012.         var menu = su_get_element("su_overflow_menu");
  20013.         menu.collapsed = false;
  20014.         menu.hidden = false;
  20015.     }
  20016.     su_cleanup_overflow_flexbox()
  20017. }
  20018.  
  20019. // handles the left margin splitter mousedown event
  20020. function su_handle_splitter_first_mousedown(event)
  20021. {
  20022.     su_moving_splitter = true;
  20023.     return true;
  20024. }
  20025.  
  20026. // handles the left margin splitter mouseup event
  20027. function su_handle_splitter_first_mouseup(event)
  20028. {
  20029.     su_moving_splitter = false;
  20030.     setTimeout("su_refresh_splitters(false)", 0);
  20031.     return true;
  20032. }
  20033.  
  20034. // handles the sidebar splitter mouseup event
  20035. function su_handle_sidebar_mouseup(event)
  20036. {
  20037.     setTimeout("su_refresh_splitters(false)", 0);
  20038.     return true;
  20039. }
  20040.  
  20041. // handles the sidebar splitter attr modified event
  20042. function su_handle_sidebar_attr_modified(event)
  20043. {
  20044.     if (event.attrName == "hidden")
  20045.         setTimeout("su_refresh_splitters(false)", 0);
  20046.  
  20047.     return true;
  20048. }
  20049.  
  20050. // queues a change to the hidden state of a top-level toolbar element
  20051. function su_set_visible(id, state)
  20052. {
  20053.     state = ! state;
  20054.     var element = su_get_element(id);
  20055.     var changed = false;
  20056.     if (element.parentNode.id == "su_overflow_popup")
  20057.     {
  20058.         if (element.hasAttribute("savedhidden"))
  20059.             element.setAttribute("savedhidden", state);
  20060.         else
  20061.             element.collapsed = state;
  20062.     }
  20063.     else
  20064.     {
  20065.         if (element.hasAttribute("su_ismode"))
  20066.         {
  20067.             changed = (element.hidden != state);
  20068.             element.hidden = state;
  20069.         }
  20070.         else
  20071.         {
  20072.             changed = (element.collapsed != state);
  20073.             element.collapsed = state;
  20074.         }
  20075.     }
  20076.     
  20077.     if ((! state) && (id == "su_referred"))
  20078.         setTimeout(su_stop_referred_throbber, su_ds.getValue("$referral_throbber_interval_ms")) 
  20079.     
  20080.     if (changed)
  20081.         setTimeout("su_reflow_toolbar(8)", 10);
  20082. }
  20083.  
  20084. function su_stop_referred_throbber()
  20085. {
  20086.     su_set_attribute("su_referred", "busy", "false");
  20087. }
  20088.  
  20089. // for future use, to fix the textonly bug
  20090. //function su_is_toolbar_textonly()
  20091. //{
  20092. //    var toolbar = su_get_parent_toolbar(su_get_element("su_stumble"));
  20093. //    if (! toolbar)
  20094. //        return false;
  20095. //    
  20096. //    if (toolbar.hasAttribute("mode") &&
  20097. //                (toolbar.getAttribute("mode") == "text"))
  20098. //        return true;
  20099. //}
  20100.  
  20101. // queues a change to the label of a top-level toolbar element
  20102. function su_set_label(id, str)
  20103. {
  20104.     var element = su_get_element(id);
  20105.     var menuified = (element.parentNode.id == "su_overflow_popup");
  20106.  
  20107.     if (id == "su_mode")
  20108.     {
  20109.         su_get_element("su_mode_label").collapsed = (! su_get_label_visibility(id, menuified));
  20110.         return;
  20111.     }
  20112.     else if (id == "su_category")
  20113.     {
  20114.         str += " ";
  20115.     }
  20116.  
  20117.     // When str is null, use the value in the showlabel attribute.
  20118.     // -- JW
  20119.  
  20120.     if (su_get_label_visibility(id, menuified))
  20121.     {
  20122.         if ((! str) && element.hasAttribute("showlabel"))
  20123.             str = element.getAttribute("showlabel");
  20124.     }
  20125.     else
  20126.     {
  20127.         str = "";
  20128.     }
  20129.  
  20130.     var changed = (element.label != str);
  20131.     str = (str) ? str : "";
  20132.     
  20133.     if (str == "")
  20134.     {
  20135.         if (menuified)
  20136.             element.className = "su-hidetext-menuified";
  20137.         else
  20138.             element.className = "su-hidetext";
  20139.     }
  20140.     else
  20141.     {
  20142.         if (menuified)
  20143.             element.className = "su-showtext-menuified";
  20144.         else
  20145.         {
  20146.             if ((element.id == "su_category") || 
  20147.                 (element.id == "su_stumble_topic"))
  20148.                 element.className = "su-hideicon-showtext";
  20149.             else
  20150.                 element.className = "su-showtext";
  20151.         }
  20152.         element.label = str;
  20153.     }
  20154.     
  20155.     if (changed)
  20156.         setTimeout("su_reflow_toolbar(9)", 10);
  20157. }
  20158.  
  20159. function su_set_attribute(id, attr_name, value)
  20160. {
  20161.     var el = su_get_element(id);
  20162.     if (! el)
  20163.         return;
  20164.     el.setAttribute(attr_name, value);
  20165. }
  20166.  
  20167. function su_remove_attribute(id, attr_name, value)
  20168. {
  20169.     var el = su_get_element(id);
  20170.     if (! el)
  20171.         return;
  20172.     if (el.hasAttribute(attr_name))
  20173.         el.removeAttribute(attr_name);
  20174. }
  20175.  
  20176. // used by the toolbar refresh routines to determine whether the 
  20177. // label associated with a top-level toolbar element is to be 
  20178. // displayed when it has the specified menuified state
  20179. function su_get_label_visibility(id, menuified)
  20180. {
  20181.     var always_visible_ids = ",su_login,su_start,su_referred,su_site-count-box,su_recthumbup,su_category,su_stumble_topic," +
  20182.                 "su_stumble_topic_menu_left,su_stumble_topic_menu_right," +
  20183.                 "su_page_feature_prompt,su_grab,su_approve,su_idx,su_tld,";
  20184.     var text_icons_mode_visible_ids = ",su_stumble,su_thumbup,su_profile," + 
  20185.                 "su_friends,su_referral_menu,firstrater,su_sponsor," + 
  20186.                 "su_mode,su_stumble_menu,su_website_info,";
  20187.     var element = su_get_element(id);
  20188.     var query = "," + id + ",";
  20189.     
  20190.     if ((stumbleid != 0) && su_ds.getValue("$show_firstrater_label_always"))
  20191.         always_visible_ids += "firstrater,su_sponsor,";
  20192.     
  20193.     if (su_promo_mode && (stumbleid == 0))
  20194.         always_visible_ids += "su_referral_promo,su_website_info_promo,su_sites_promo,su_video_promo,"
  20195.     
  20196.     var text_icons = true;
  20197.     
  20198.     if (stumbleid != 0)
  20199.         text_icons = (su_ds.getValue("$icons") == "text-icons"); 
  20200.     
  20201.     // Visible if:
  20202.     // (1) it's always visible
  20203.     // (2) we're configured to text-icons, and this is in the visible subset
  20204.     // (3) it's in the overflow popup, and it has a showlabel attribute
  20205.     // -- JW
  20206.     return (always_visible_ids.indexOf(query) != -1) ||
  20207.                 (text_icons && 
  20208.                 (text_icons_mode_visible_ids.indexOf(query) != -1)) ||
  20209.                 (menuified && element.hasAttribute("showlabel") && 
  20210.                     (id != "su_mode"));
  20211. }
  20212.  
  20213. // queues a change to the image of a top-level toolbar element
  20214. function su_set_image(id, uri)
  20215. {
  20216.     var element = su_get_element(id);
  20217.  
  20218.     var changed = (element.image != uri);
  20219.     if (changed)
  20220.     {
  20221.         element.image = uri;
  20222.         setTimeout("su_reflow_toolbar(10)", 10);
  20223.     }
  20224. }
  20225.  
  20226. // used by splitter mouseup handlers and the splitter init routine to
  20227. // set splitter visibility and to store new state
  20228. function su_refresh_splitters(use_saved_latch_state)
  20229. {
  20230.     try {
  20231.     var content_x = su_get_element("content").boxObject.x;
  20232.     var toolbar_x = su_get_element("su_stumble").boxObject.x;
  20233.     var sidebar_hidden = su_get_element("sidebar-splitter").hidden || 
  20234.                 su_get_element("sidebar-box").collapsed;
  20235.     var align_with_content = su_ds.getValue("@latch-to-sidebar");
  20236.     var splitter_first = su_get_element("su_splitter_first");
  20237.     var first_flexbox = su_get_element("su_splitter_first_flexbox");
  20238.     
  20239.     var splitter = su_get_element("su_right-justify-splitter")
  20240.  
  20241.     if ((su_toolbar_justification == "left") && (splitter))
  20242.     {
  20243.         splitter.parentNode.removeChild(splitter);
  20244.     }
  20245.     else if ((su_toolbar_justification == "right") && (! splitter))
  20246.     {
  20247.         var splitter = document.createElement("splitter");
  20248.         splitter.setAttribute("id", "su_right-justify-splitter");
  20249.         splitter.setAttribute("class", "su_splitter");
  20250.         splitter.setAttribute("state", "open");
  20251.         splitter.setAttribute("collapse", "none");
  20252.         splitter.setAttribute("resizebefore", "grow");
  20253.         splitter.setAttribute("resizeafter", "closest");
  20254.         splitter.setAttribute("onmousedown", "return su_handle_right_justify_splitter_mousedown(event);");
  20255.         splitter.setAttribute("onmouseup", "return su_handle_right_justify_splitter_mouseup(event);");
  20256.         
  20257.         var sibling = su_get_toolbar_outer_container();
  20258.         sibling.parentNode.insertBefore(splitter, sibling);
  20259.     }
  20260.     else if ((su_toolbar_justification == "right") && (splitter))
  20261.     {
  20262.         splitter.collapsed = false;
  20263.         var sibling = su_get_toolbar_outer_container();
  20264.         
  20265.         sibling.parentNode.insertBefore(splitter, sibling);
  20266.     }
  20267.     
  20268.     // Determine whether the toolbar should be latched to the sidebar.
  20269.     if (su_is_toolbar_shared())
  20270.     {
  20271.         align_with_content = false;
  20272.         splitter_first.collapsed = true;
  20273.     }
  20274.     else if (su_ds.getValue("@toolbar-position") == "stumbleupon")
  20275.     {
  20276.         splitter_first.collapsed = sidebar_hidden;
  20277.         if (! use_saved_latch_state)
  20278.         {
  20279.             if ((su_sidebar_was_hidden == sidebar_hidden) && (su_old_toolbar_x != toolbar_x))
  20280.             {
  20281.                 var latch_to_sidebar = su_ds.getValue("@latch-to-sidebar");
  20282.                 
  20283.                 if (latch_to_sidebar)
  20284.                     align_with_content = (toolbar_x >= (content_x - 20));
  20285.                 else
  20286.                     align_with_content = (first_flexbox.boxObject.width > 20);
  20287.             }
  20288.             su_ds.setValue("@latch-to-sidebar", align_with_content);
  20289.         }
  20290.     }
  20291.     else
  20292.     {
  20293.         align_with_content = false;
  20294.         splitter_first.collapsed = true;
  20295.     }
  20296.  
  20297.     var new_width;
  20298.     if (align_with_content)
  20299.     {
  20300.         // If latched, move the toolbar to match.
  20301.     
  20302.         if (sidebar_hidden)
  20303.         {
  20304.             new_width = 0;
  20305.         }
  20306.         else
  20307.         {
  20308.             // This hidden statement works around an apparent browser bug
  20309.             // (ref: Firefox 2.0.0.2, Linux). -- JW
  20310.             splitter_first.hidden = false;
  20311.             new_width = content_x - first_flexbox.boxObject.x - splitter_first.boxObject.width;
  20312.             if (new_width < 0)
  20313.                 new_width = 0;
  20314.         }
  20315.     }
  20316.     else
  20317.     {
  20318.         new_width = 0;
  20319.     }
  20320.     first_flexbox.setAttribute("width", new_width + "px");
  20321.     
  20322.     var search = su_get_element("su_field");
  20323.     if (! search.collapsed)
  20324.     {
  20325.         var width = search.boxObject.width;
  20326.         if (width != 0)
  20327.         {
  20328.             // The zero test above fixes an issue where the search box 
  20329.             // width gets set to zero upon toggling visibility (ref: 
  20330.             // Firefox 1.5, XP). -- JW
  20331.             su_ds.setValue("@search-width", width);
  20332.         }
  20333.     }
  20334.     su_old_toolbar_x = su_get_element("su_stumble").boxObject.x;
  20335.     su_sidebar_was_hidden = sidebar_hidden;
  20336.     su_reflow_toolbar(11);
  20337.     if (su_bookmarks_sibling_loc)
  20338.         su_reflow_bookmarks_toolbar();
  20339.     
  20340.     } catch (e) { su_log_error("REFRESH SPLITTERS", e, su_ds.getValue("@toolbar-position"), su_ds.getValue("@position-group")); }
  20341. }
  20342.     
  20343. // handles the window resize event
  20344. function su_handle_window_resize(event)
  20345. {
  20346.     var width = window.innerWidth;
  20347.     
  20348.     if (width != su_resize_window_width)
  20349.     {
  20350.         su_resize_window_width = width;
  20351.         su_reflow_toolbar(12);
  20352.     }
  20353.     else if (! su_resize_window_dirty)
  20354.     {
  20355.         // handles window maximize case
  20356.         su_resize_window_dirty = true;
  20357.         setTimeout(su_handle_window_resize2, 500);
  20358.     }
  20359.  
  20360.     return true;
  20361. }
  20362.  
  20363. function su_handle_window_resize2()
  20364. {
  20365.     if (! su_resize_window_dirty)
  20366.         return;
  20367.     
  20368.     su_reflow_toolbar(14);
  20369.     
  20370.     su_resize_window_dirty = false;
  20371. }
  20372.  
  20373. function su_reflow_toolbar(from)
  20374. {
  20375.     try {
  20376.     if (! su_gui_initialized)
  20377.         return;    
  20378.  
  20379.     // Nuke the flexbox.
  20380.     var flexbox = su_get_element("su_overflow_flexbox"); 
  20381.     if (flexbox)
  20382.         flexbox.parentNode.removeChild(flexbox);
  20383.     
  20384.     var container = su_get_element("su_stumble").parentNode;
  20385.     var outer_container = su_get_toolbar_outer_container();
  20386.     
  20387.     if (container.id == "su_container")
  20388.     {
  20389.         container.setAttribute("flex", "1");
  20390.     }
  20391.     else
  20392.     {
  20393.         var hbox = su_get_element("su_container");
  20394.         if (hbox.hasAttribute("flex"))
  20395.             hbox.removeAttribute("flex");
  20396.     }
  20397.  
  20398.     // If we're invisible, hide the outer_container.
  20399.     if (! su_ds.getValue("@toolbar-visible"))
  20400.     {
  20401.         outer_container.setAttribute("width", 0);
  20402.         return;
  20403.     }
  20404.     
  20405.     // Demenuify everything.
  20406.     var popup = su_get_element("su_overflow_popup"); 
  20407.     while (popup.hasChildNodes())
  20408.         su_demenuify_toolbar_element(popup.firstChild);
  20409.     
  20410.     var sibling;
  20411.     sibling = su_get_element("su_stumble").parentNode.firstChild;
  20412.     while (sibling)
  20413.     {
  20414.         sibling.hidden = false;
  20415.         sibling = sibling.nextSibling;
  20416.     }
  20417.  
  20418.     var position = su_ds.getValue("@toolbar-position");
  20419.     if ((position == "gtbToolbar") && (! su_reflow_delayed))
  20420.     {
  20421.         // If we're on the google toolbar, expand to max width, and allow
  20422.         // the toolbar to reflow.
  20423.         outer_container.setAttribute("width", 
  20424.                     container.lastChild.boxObject.x + 
  20425.                     container.lastChild.boxObject.width - 20 + "px");
  20426.         su_reflow_delayed = true;
  20427.         setTimeout(su_reflow_toolbar, 0, 13);
  20428.         return;
  20429.     }
  20430.     su_reflow_delayed = false;
  20431.  
  20432.     var menu = su_get_element("su_overflow_menu");
  20433.     menu.collapsed = false;
  20434.     var chevron_width = menu.boxObject.width;
  20435.     menu.collapsed = true;
  20436.     
  20437.  
  20438.     // Compute available width.
  20439.  
  20440.     var toolbar = su_get_element(su_get_parent_toolbar_id(container));
  20441.     var available = window.innerWidth;
  20442.     var regexp = new RegExp("^spring\\d+$");
  20443.     var i;
  20444.     var in_toolbar_elements = false;
  20445.     var google_sibling_found = false;
  20446.     var has_flexible_sibling = false;
  20447.     var max;
  20448.     for (i = 0; i < toolbar.childNodes.length; i++)
  20449.     {
  20450.         var sibling = toolbar.childNodes[i];
  20451.         var pre = available;
  20452.         var id = (sibling.id) ? sibling.id : "";
  20453.         if (id == "su_splitter_first_flexbox")
  20454.         {
  20455.             in_toolbar_elements = true;
  20456.         }
  20457.         else if (in_toolbar_elements)
  20458.         {
  20459. //            if (su_host.mac)
  20460. //                sibling.hidden = false;
  20461.             
  20462.             if (id == "su_overflow_menu")
  20463.             {
  20464.                 in_toolbar_elements = false;
  20465.                 max = sibling.boxObject.x + sibling.boxObject.width;
  20466.             }
  20467.         }
  20468.         else if (id == "nav-bar-inner")
  20469.         {
  20470.             available -= 300;  // Seamonkey url bar
  20471.         }
  20472.         else if (id == "urlbar-container")
  20473.         {
  20474.             available -= 300;  // Firefox url bar
  20475.         }
  20476.         else if ((id == "search-container") && sibling.hasAttribute("flex"))
  20477.         {
  20478.             available -= 185;  // Firefox search box for 2.0+
  20479.         }
  20480.         else if (id == "statusbar-display")
  20481.         {
  20482.             available -= 185;  // Status bar content
  20483.         }
  20484.         else if ((id != "su_toolbaritem") && 
  20485.                     (id != "su_toolbar_container") &&
  20486.                     (id != "su_statusbar_container") &&
  20487.                     (id != "su_otherbar_container") &&
  20488.                     (id != "su_googlebar_container") &&
  20489.                     (id != "su_container") &&
  20490.                     (id != "bookmarks-ptf") &&        // Seamonkey bookmarks
  20491.                     (id != "personal-bookmarks") &&   //   Firefox bookmarks
  20492.                     (sibling.tagName != "tooltip") && // Seamonkey tooltips
  20493.                     (id.search(regexp) != 0))
  20494.         {
  20495.             if (sibling.boxObject.width != 0)
  20496.                 google_sibling_found = true;
  20497.             available -= sibling.boxObject.width;
  20498.         }
  20499.     }
  20500.     
  20501.     if (su_toolbar_justification == "right")
  20502.     {
  20503.         // If we're right-justified, limit to @right-justify-width.
  20504.         var justify_width = su_ds.getValue("@right-justify-width");
  20505.  
  20506.         if (available > justify_width)
  20507.             available = justify_width;
  20508.     }
  20509.     else if (position == "gtbToolbar")
  20510.     {
  20511.         var gtb_chevron = su_get_element("gtbChevron");
  20512.         if (google_sibling_found)
  20513.         {
  20514.             // Leave the previously set max width.
  20515.             if (gtb_chevron)
  20516.                 gtb_chevron.collapsed = false;
  20517.             return;
  20518.         }
  20519.         else
  20520.         {
  20521.             // Limit width to window width.
  20522.             if (gtb_chevron)
  20523.                 gtb_chevron.collapsed = true;
  20524.  
  20525.             available = window.innerWidth;
  20526.             container.setAttribute("width", available + "px");
  20527.         }
  20528.     }
  20529.     else
  20530.     {
  20531.         if (su_ds.getValue("@position-group") == "first")
  20532.         {
  20533.             // Push companion elements to the right.
  20534.             available = document.getElementById("main-window").boxObject.width;
  20535.         }
  20536.         
  20537. //        if ((! max) && (su_ds.getValue("@toolbar-position") != "stumbleupon"))
  20538.         if (! max)
  20539.         {
  20540.             var box = su_get_element("su_overflow_menu").boxObject;
  20541.             max = box.x + box.width;
  20542.         }
  20543.         
  20544. //        if ((outer_container.id != "status-bar") && 
  20545. //                    (su_ds.getValue("@toolbar-position") != "stumbleupon"))
  20546.         if (outer_container.id != "status-bar")
  20547.         {
  20548.             if (available > max)
  20549.                 available = max;
  20550.             outer_container.setAttribute("width", available + "px");
  20551.         }
  20552.     }
  20553.  
  20554.     // For each element that won't fit, move it into the overflow menu.
  20555.     var overflowed = false;
  20556.     var first = true;
  20557.     in_toolbar_elements = false;
  20558.     for (i = container.childNodes.length - 2; i >= 0; i--)
  20559.     {
  20560.         var item = container.childNodes[i];
  20561.  
  20562.         var consumed = item.boxObject.x - container.boxObject.x + 
  20563.                     item.boxObject.width + ((first) ? 0 : chevron_width);
  20564.         
  20565.         first = false;
  20566.         
  20567.         var id = (item.id) ? item.id : "";
  20568.         
  20569.         if ((id == "su_overflow_menu") || (id == "su_site-count-box"))
  20570.         {
  20571.             in_toolbar_elements = true;
  20572.             if (id == "su_overflow_menu")
  20573.                 continue;
  20574.         }
  20575.         if (! in_toolbar_elements)
  20576.         {
  20577.             continue;
  20578.         }
  20579.         else if ((consumed > available) && (id != "su_thumbdown"))
  20580.         {
  20581.             overflowed = true;
  20582.             su_menuify_toolbar_element(item);
  20583.         }
  20584.         else
  20585.         {
  20586.             if (id.indexOf("su_separator") == 0)
  20587.                 su_menuify_toolbar_element(item);
  20588.             break;
  20589.         }
  20590.     }
  20591.     
  20592.     if (overflowed)
  20593.     {
  20594.         menu.collapsed = false;
  20595.         su_cleanup_overflow_menuseparators();
  20596.     }
  20597.     su_cleanup_overflow_flexbox();
  20598.  
  20599.     sibling = su_get_element("su_stumble").parentNode.firstChild;
  20600.     while (sibling)
  20601.     {
  20602.         sibling.hidden = sibling.collapsed;
  20603.         sibling = sibling.nextSibling;
  20604.     }
  20605.     
  20606.     setTimeout(su_refresh_info, 0);
  20607.     
  20608.     if (from != "retry")
  20609.         setTimeout(su_verify_reflow, 500);
  20610.     
  20611.     }
  20612.     catch (e) {
  20613.         var toolbar_position = su_ds.getValue("@toolbar-position");
  20614.         var position_group = su_ds.getValue("@position-group");
  20615.         if ((toolbar_position == "stumbleupon") && (position_group == "first"))
  20616.         {
  20617.             su_log_error("REFLOW ERROR", e, from);
  20618.         }
  20619.         else
  20620.         {
  20621.             su_log_error("REFLOW FAILSAFE", e, from, toolbar_position, position_group);
  20622.             su_ds.setValue("@toolbar-position", "stumbleupon");
  20623.             su_ds.setValue("@position-group", "first");
  20624.         }
  20625.     }
  20626.     
  20627. }
  20628.  
  20629. function su_reflow_bookmarks_toolbar()
  20630. {
  20631.     if (su_get_element("bookmarks-ptf") && window.BMSVC
  20632.             && ((typeof (window.BMSVC.getBookmarksToolbarFolder)) == "function")
  20633.             && window.BookmarksToolbarRDFObserver)
  20634.     {
  20635.         // ref: Firefox 2.0
  20636.         var bt = su_get_element("bookmarks-ptf");
  20637.         var btf = BMSVC.getBookmarksToolbarFolder().Value;
  20638.         var btchevron = document.getElementById("bookmarks-chevron");
  20639.         bt.ref = btf;
  20640.         btchevron.ref = btf;
  20641.         // no uniqueness is guaranteed, so we have to remove first
  20642.         try {
  20643.             bt.database.RemoveObserver(BookmarksToolbarRDFObserver);
  20644.         } catch (ex) {
  20645.             // ignore
  20646.         }
  20647.         bt.database.AddObserver(BookmarksToolbarRDFObserver);
  20648.         bt.builder.rebuild();
  20649.         btchevron.builder.rebuild();
  20650.  
  20651.         // fake a resize; this function takes care of flowing bookmarks
  20652.         // from the bar to the overflow item
  20653.         BookmarksToolbar.resizeFunc(null);
  20654.     }
  20655.     else if (su_get_element("bookmarksBarContent")
  20656.         && (typeof (su_get_element("bookmarksBarContent").updateChevron) == "function"))
  20657.             
  20658.     {
  20659.         // ref: Firefox 3.6rc
  20660.         var bar_content = su_get_element("bookmarksBarContent");
  20661.         bar_content.updateChevron();
  20662.     }
  20663. }    
  20664.  
  20665. function su_verify_reflow()
  20666. {
  20667.     //!!! This is very primitive; it only helps when the stumbleupon 
  20668.     // elements are the last time on the bar.  This is the most common
  20669.     // case.  Eventually, we have to discover why it's necessary at all
  20670.     // an why it's off by 2 px every time.
  20671.     var box = su_get_element("su_overflow_menu").boxObject;
  20672.     
  20673.     if (((box.x + box.width) - window.innerWidth) > 3)
  20674.     {
  20675.         setTimeout(su_reflow_toolbar, 0, "retry");
  20676.     }
  20677. }
  20678.  
  20679. function su_cleanup_toolbox(force, update_urlbar)
  20680. {
  20681.     var position = su_ds.getValue("@toolbar-position");
  20682.  
  20683.     if ((force || (position == "gtbToolbar")) && 
  20684.                 ((typeof GTB_GoogleToolbarOverlay) != "undefined") && 
  20685.                 GTB_GoogleToolbarOverlay.chevron && 
  20686.                 ((typeof GTB_GoogleToolbarOverlay.chevron.doResize) == 
  20687.                 "function"))
  20688.     {
  20689.         try {
  20690.             GTB_GoogleToolbarOverlay.chevron.doResize();
  20691.         } catch (e) {};
  20692.     }
  20693.     
  20694.     if ((force || (position == "yahoo-toolbar")) &&
  20695.                 ((typeof yahooToolbarOverflowDelay) == "function"))
  20696.     {
  20697.         try {
  20698.             yahooToolbarOverflowDelay();
  20699.         } catch (e) {};
  20700.     }
  20701.     
  20702.     try {
  20703.         su_reflow_bookmarks_toolbar();
  20704.     } catch (e) { su_log("BOOKMARKS CLEANUP", e); }
  20705.     
  20706.     if ((force || (position == "prefbar")) &&
  20707.                 ((typeof prefbarUpdateToolbar) == "function"))
  20708.     {
  20709.         setTimeout(prefbarUpdateToolbar, 0);
  20710.     }
  20711.  
  20712.     if (update_urlbar)
  20713.     {
  20714.         try {
  20715.         // Update the urlbar
  20716.             var url = getWebNavigation().currentURI.spec;
  20717.             if (window.gURLBar)
  20718.             {
  20719.                 if (url == "about:blank")
  20720.                 {
  20721.                     gURLBar.value = "";
  20722.                     SetPageProxyState("invalid");
  20723.                 }
  20724.                 else
  20725.                 {
  20726.                     gURLBar.value = url;
  20727.                     SetPageProxyState("valid");
  20728.                 }
  20729.                 FeedHandler.updateFeeds();
  20730.             }
  20731.         } catch (e) {}
  20732.     }
  20733. }
  20734.  
  20735. // used by shorten_toolbar to move an element from the toolbar to the
  20736. // overflow menu
  20737. function su_menuify_toolbar_element(element)
  20738. {
  20739.     var popup = su_get_element("su_overflow_popup");
  20740.     
  20741.     var new_element;
  20742.     if ((element.id == "su_referral_menu") || (element.id == "su_stumble_menu"))
  20743.     {
  20744.         new_element = element;
  20745.         new_element.label = new_element.getAttribute("showlabel");
  20746.     }
  20747.     else if (element.id == "su_mode")
  20748.     {
  20749.         new_element = element;
  20750.         su_get_element("su_mode_label").collapsed = true;
  20751.     }
  20752.     else if (element.id == "su_field")
  20753.     {
  20754.         new_element = element;
  20755.         new_element.setAttribute("savedhidden", new_element.collapsed);
  20756.         new_element.collapsed = true;
  20757.     }
  20758.     else if (element.tagName == "splitter")
  20759.     {
  20760.         new_element = element.cloneNode(true);
  20761.         new_element.setAttribute("savedhidden", new_element.collapsed);
  20762.         new_element.collapsed = true;
  20763.     }
  20764.     else if ((element.tagName == "toolbarbutton") && element.hasAttribute("showlabel"))
  20765.     {
  20766.         new_element = element.cloneNode(true);
  20767.         new_element.label = new_element.getAttribute("showlabel");
  20768.     }
  20769.     else if (element.id.indexOf("su_separator") == 0)
  20770.     {
  20771.         new_element = document.createElement("menuseparator");
  20772.         new_element.id = element.id;
  20773.         new_element.collapsed = element.collapsed;
  20774.     }
  20775.     else
  20776.     {
  20777.         new_element = element.cloneNode(true);
  20778. //        new_element.hidden = element.collapsed;
  20779. //        new_element.collapsed = false;
  20780.     }
  20781.  
  20782.     element.parentNode.removeChild(element);
  20783.  
  20784.     if (new_element.className == "su-showtext")
  20785.         new_element.className =  "su-showtext-menuified";
  20786.  
  20787.     else if (new_element.className == "su-hidetext")
  20788.         new_element.className = "su-hidetext-menuified";
  20789.     
  20790.     new_element.hidden = new_element.collapsed;
  20791.     
  20792.     popup.insertBefore(new_element, popup.firstChild);
  20793. }
  20794.  
  20795. // used by lengthen_toolbar to move an element from the overflow menu
  20796. // to the toolbar
  20797. function su_demenuify_toolbar_element(element)
  20798. {
  20799.     var new_element;
  20800.  
  20801.     if (element.id == "su_field")
  20802.     {
  20803.         new_element = element;
  20804.         new_element.collapsed = (new_element.getAttribute("savedhidden") == "true");
  20805.         new_element.removeAttribute("savedhidden");
  20806.     }
  20807.     else if (element.id == "su_mode")
  20808.     {
  20809.         new_element = element;
  20810.         su_get_element("su_mode_label").collapsed = (su_ds.getValue("$icons") == "icons-only");
  20811.     }
  20812.     else if (element.tagName == "splitter")
  20813.     {
  20814.         new_element = element.cloneNode(true);
  20815.         new_element.collapsed = (new_element.getAttribute("savedhidden") == "true");
  20816.         new_element.removeAttribute("savedhidden");
  20817.     }
  20818.     else if (element.id.indexOf("su_separator") == 0)
  20819.     {
  20820.         // These DIVs fix the bug where spurious separators were appearing
  20821.         // after the user Customizes the toolbar area in Firefox.
  20822.         // Analysis:
  20823.         // Customize stores element ids in localstore.rdf, but it doesn't
  20824.         // save the ids of separators (since they have identical 
  20825.         // rendering).  Upon restart, ids duplicated elsewhere by our 
  20826.         // toolbar elements are ignored, but the unlabeled separators
  20827.         // remain where Customize recorded them to be.  Workaround is to
  20828.         // wrap our separators so that an id will be recorded. -- JW
  20829.  
  20830.         new_element = document.createElement("div");
  20831.         new_element.id = element.id;
  20832.         var tmp = document.createElement("toolbarseparator");
  20833.         new_element.appendChild(tmp);
  20834.  
  20835.         if (element.hasAttribute("savedhidden"))
  20836.             new_element.collapsed = (element.getAttribute("savedhidden") == "true");
  20837.         else
  20838.             new_element.collapsed = element.collapsed;
  20839.     }
  20840.     else if (element.tagName == "toolbarbutton")
  20841.     {
  20842.         new_element = element.cloneNode(true);
  20843.         if (! su_get_label_visibility(element.id, false))
  20844.             new_element.label = "";
  20845.     }
  20846.     else
  20847.     {
  20848.         new_element = element.cloneNode(true);
  20849. //        new_element.collapsed = element.hidden;
  20850. //        new_element.hidden = false;
  20851.     }
  20852.     
  20853.     var next_sibling = su_get_element("su_overflow_menu");
  20854.  
  20855.     if (next_sibling.previousSibling.id == "su_overflow_flexbox")
  20856.     {
  20857.         // Skip the flexbox.
  20858.         next_sibling = next_sibling.previousSibling;
  20859.     }
  20860.  
  20861.     if (new_element.hasAttribute("savedwidth"))
  20862.         new_element.removeAttribute("savedwidth");
  20863.  
  20864.     element.parentNode.removeChild(element);
  20865.     
  20866.     next_sibling.parentNode.insertBefore(new_element, next_sibling);
  20867.     
  20868.     //!!! This may be causing a reflow bug; new width may not be
  20869.     //    set soon enough for it to be used in the reflow calculation.
  20870.     //    -- JW
  20871.     if (new_element.className == "su-showtext-menuified")
  20872.         new_element.className = "su-showtext";
  20873.  
  20874.     if (new_element.className == "su-hidetext-menuified")
  20875.         new_element.className = "su-hidetext";
  20876. }
  20877.  
  20878. // used by refresh_toolbar_gated() to add or destroy the overflow 
  20879. // flexbox as required
  20880. function su_cleanup_overflow_flexbox()
  20881. {
  20882.     var menu = su_get_element("su_overflow_menu");
  20883.     // The overflow flexbox right-justifies the overflow menu when the 
  20884.     // toolbar elements are in the stumbleupon toolbar or are 
  20885.     // right-justified. -- JW
  20886.     if (((menu.parentNode.id == "su_container") || 
  20887.                 (menu.parentNode.id == "su_toolbar_container") || 
  20888.                 (menu.parentNode.id == "su_statusbar_container") || 
  20889.                 (menu.parentNode.id == "su_otherbar_container") || 
  20890.                 (menu.parentNode.id == "su_googlebar_container")) && 
  20891.                 (menu.previousSibling.id != "su_overflow_flexbox"))
  20892.     {
  20893.         var flexbox = document.createElement("vbox");
  20894.         flexbox.setAttribute("id", "su_overflow_flexbox");
  20895.         flexbox.setAttribute("flex", "1");
  20896.  
  20897.         menu.parentNode.insertBefore(flexbox, menu);
  20898.     }
  20899.     else if ((menu.parentNode.id != "su_container") && 
  20900.                 (menu.parentNode.id != "su_toolbar_container") && 
  20901.                 (menu.parentNode.id != "su_statusbar_container") &&
  20902.                 (menu.parentNode.id != "su_otherbar_container") &&
  20903.                 (menu.parentNode.id != "su_googlebar_container") &&
  20904.                 (menu.previousSibling.id == "su_overflow_flexbox"))
  20905.     {
  20906.         menu.parentNode.removeChild(menu.previousSibling);
  20907.     }
  20908. }
  20909.  
  20910. // used by refresh_toolbar_gated() to make sure the top item in the 
  20911. // overflow menu isn't a menuseparator
  20912. function su_cleanup_overflow_menuseparators()
  20913. {
  20914.     try {
  20915.     var sibling = su_get_element("su_overflow_popup").firstChild;
  20916.  
  20917.     var before_first_visible_element = true;
  20918.  
  20919.     while (sibling)
  20920.     {
  20921.         if (sibling.collapsed)
  20922.         {
  20923.             sibling = sibling.nextSibling;
  20924.             continue;
  20925.         }
  20926.         else if (sibling.tagName == "menuseparator")
  20927.         {
  20928.             if (before_first_visible_element)
  20929.             {
  20930.                 before_first_visible_element = false;
  20931.                 sibling.setAttribute("savedhidden", "false");
  20932.                 sibling.collapsed = true;
  20933.             }
  20934.             else
  20935.             {
  20936.                 if (sibling.hasAttribute("savedhidden"))
  20937.                 {
  20938.                     sibling.collapsed = (sibling.getAttribute("savedhidden") == "true");
  20939.                     sibling.removeAttribute("savedhidden");
  20940.                 }
  20941.             }
  20942.         }
  20943.         else
  20944.         {
  20945.             before_first_visible_element = false;
  20946.         }
  20947.         sibling = sibling.nextSibling;
  20948.     }
  20949.     } catch (e) { su_log_error("CLEANUP MENUSEPARATORS", e, su_ds.getValue("@toolbar-position"), su_ds.getValue("@position-group")); }
  20950. }
  20951.  
  20952. // handles the popuphiding event for the overflow menu popup; sets a
  20953. // flag that delays toolbar refresh
  20954. function su_handle_popupshowing(event)
  20955. {
  20956.     switch (event.target.id)
  20957.     {
  20958.         case "su_referred_popup":  su_referred_popup_open = true; break;
  20959.         case "su_referral_popup":  su_referral_popup_open = true; break;
  20960.         case "su_mode_more_popup": su_mode_more_popup_open = true; break;
  20961.         case "su_overflow_popup":  su_overflow_popup_open = true; break;
  20962.     }
  20963. }
  20964.  
  20965. // handles the popuphidden event for the overflow menu popup; clears
  20966. // a flag that otherwise delays toolbar refresh
  20967. function su_handle_popuphidden(event)
  20968. {
  20969.     switch (event.target.id)
  20970.     {
  20971.         case "su_referred_popup":
  20972.             su_referred_popup_open = false;
  20973.             break;
  20974.         case "su_referral_popup":
  20975.             su_referral_popup_open = false;
  20976.             su_refresh_referral_menu(8);
  20977.             break;
  20978.         case "su_mode_more_popup":
  20979.             su_mode_more_popup_open = false;
  20980.             su_refresh_dyn_channels();
  20981.             break;
  20982.         case "su_overflow_popup":
  20983.             su_overflow_popup_open = false;
  20984.             break;
  20985.     }
  20986. }
  20987.  
  20988. function su_show_search_dialog(new_tab)
  20989. {
  20990.     var detail = new Object();
  20991.     detail.query = "";
  20992.     detail.query_default = su_get_element("su_searchbox").value;
  20993.     detail.new_tab = new_tab;
  20994.     if (detail.query_default == su_tag_instructions)
  20995.         detail.query_default = "";
  20996.  
  20997.     window.openDialog(
  20998.                 "chrome://stumbleupon/content/searchDialog.xul",
  20999.                 "",
  21000.                 "chrome,dialog,centerscreen,dependent",
  21001.                 detail);
  21002. }
  21003.  
  21004. function su_search_dialog_accept(detail)
  21005. {
  21006.     su_stumble_in_tag(su_trim(detail.query), detail.new_tab);
  21007. }
  21008.  
  21009. // old search implementations
  21010. //var theurl = "http://www.google.ca/search?q=" + escape(query);
  21011. //var theurl = "http://www.google.com/custom?q=" + escape(query) + "&sa=Search&client=pub-1501742633103790&forid=1&channel=3900634926&cof=" + escape("GFNT:#7777cc;GL:0;VLC:663399;AH:left;BGC:white;LC:#0000FF;ALC:#0000FF;T:000000;FORID:1;");
  21012. //var theurl = "http://search.stumbleupon.com/?q=" + escape(query);
  21013.  
  21014.  
  21015. function su_stumble_in_tag(tag, new_tab)
  21016. {
  21017.     if (tag == "")
  21018.         return;
  21019.  
  21020.     // put it in the box
  21021.     su_get_element("su_searchbox").value = tag;
  21022.     su_get_element("su_searchbox").removeAttribute("mode");
  21023.     su_old_search = tag;
  21024.     su_last_typed_tag = 0;
  21025.     su_visited_searchbox = 1;
  21026.  
  21027.     // select and do it
  21028.     su_select_topic('TAG_' + tag, tag, new_tab);
  21029.     
  21030.     su_previous_query_category = "TAG_" + tag;
  21031.     
  21032.     su_queries.unshift(tag);
  21033.     
  21034.     var i;
  21035.     for (i = 1; i < su_queries.length; i++)
  21036.     {
  21037.         if (su_queries[i] == tag)
  21038.         {
  21039.             // nuke duplicate
  21040.             su_queries.splice(i, 1);
  21041.             break;
  21042.         }
  21043.     }
  21044.     
  21045.     su_store_queries();
  21046. }
  21047.  
  21048. function su_skip_stumble(context)
  21049. {
  21050. //    su_dd("skip");
  21051.     // losing connectivity could cause many skips, so we stop at 3
  21052.     context.skip_count++;
  21053.     
  21054.     if (context.skip_count >= 3)
  21055.         return;
  21056.     
  21057.     su_get_unseen_url(
  21058.             context.user_cat,
  21059.             1,
  21060.             function(unseen, context) { window.stumble_done(unseen, context); },
  21061.             context);
  21062. }
  21063.  
  21064. function su_is_404_status(status)
  21065. {
  21066.     if (status == null)
  21067.         return false;
  21068.     
  21069.     switch (status)
  21070.     {
  21071.         case 401:
  21072.         case 403:
  21073.         case 404:
  21074.         case 0:
  21075.             return true;
  21076.     }
  21077.     return false;
  21078. }
  21079.  
  21080. var su_StumbleProgressListener = function (url_detail, context)
  21081. {
  21082.     this.url_detail = url_detail;
  21083.     this.context = context;
  21084.     this.skipping_stumble = false;
  21085. }
  21086.  
  21087. su_StumbleProgressListener.prototype =
  21088. {
  21089.     QueryInterface: function (iid)
  21090.     {
  21091.         if (!iid.equals(Components.interfaces.nsIWebProgressListener) &&
  21092.                 !iid.equals(Components.interfaces.nsISupportsWeakReference) && // not implemented
  21093.                 !iid.equals(Components.interfaces.nsISupports))
  21094.         {
  21095.             throw Components.errors.NS_ERROR_NO_INTERFACE;
  21096.         }
  21097.         
  21098.         return this;
  21099.     },
  21100.     
  21101.     onStateChange: function (aWebProgress, aRequest, aStateFlags, aStatus)
  21102.     {
  21103.         const nsIWPL = Components.interfaces.nsIWebProgressListener;
  21104.         var original_url;
  21105.         // do a try, we don't want to mess with state change...
  21106.         try {
  21107.             if (aWebProgress.DOMWindow != aWebProgress.DOMWindow.top)
  21108.                 return;
  21109.             
  21110.             aRequest.QueryInterface(Components.interfaces.nsIChannel);
  21111.             
  21112.             original_url = aRequest.originalURI.asciiSpec;
  21113.             
  21114.             if (original_url != this.url_detail.url)
  21115.                 return;
  21116.             
  21117.         } catch (e) { return; } // ignore error accessing DOMWindow.top
  21118.         
  21119.         try {
  21120.             if (aStateFlags & nsIWPL.STATE_STOP)
  21121.             {            
  21122.                 try {
  21123.                     var channel = this.context.target_browser.docShell.currentDocumentChannel;
  21124.                     var status = channel.responseStatus;
  21125.                     if (su_is_404_status(status))
  21126.                     {
  21127.                         if ((this.url_detail.cluster_type != 3) &&
  21128.                                 (this.url_detail.cluster_type != 4))
  21129.                         {
  21130.                             this.skipping_stumble = true;
  21131.                             setTimeout(su_skip_stumble, 0, this.context);
  21132.                         }
  21133.                         su_report_404(this.url_detail.url, status);
  21134.                     }
  21135.                 } catch (e) {}
  21136.                 this.destroy();
  21137.                 return;
  21138.             }
  21139.             
  21140.             if (this.skipping_stumble)
  21141.                 return;
  21142.             
  21143.             var redirect_url = aRequest.URI.asciiSpec;
  21144.             
  21145.             if (this.url_detail.redirect_url == redirect_url)
  21146.                 return;
  21147.             
  21148.             this.url_detail.redirect_url = redirect_url;
  21149.             
  21150.             su_ds.define("url:url_detail", redirect_url, this.url_detail);
  21151.             
  21152.             var domain = su_get_tld(redirect_url);
  21153.             
  21154.             if ((this.url_detail.cluster_type != 4) && su_is_domain_blocked(domain))
  21155.             {
  21156.                 this.skipping_stumble = true;
  21157.                 setTimeout(su_skip_stumble, 0, this.context);
  21158.             }
  21159.             else if (domain != this.url_detail.tld)
  21160.             {
  21161.                 if ((this.url_detail.cluster_type != 3) && (this.url_detail.cluster_type != 4))
  21162.                 {
  21163.                     this.skipping_stumble = true;
  21164.                     setTimeout(su_skip_stumble, 0, this.context);
  21165.                 }
  21166.                 su_report_redirect(original_url, 302, redirect_url);
  21167.             }
  21168.         } catch (e) { su_log_error("FILTER ERROR", e); }
  21169.         
  21170.     },
  21171.     
  21172.     destroy: function ()
  21173.     {
  21174.         if (! this.context)
  21175.             return;
  21176.  
  21177.         this.context.target_browser.removeProgressListener(this);
  21178.         this.context = null;
  21179.         this.url_detail = null;
  21180.     },
  21181.     
  21182.     onProgressChange: function (aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {},
  21183.     
  21184.     // see: http://developer.mozilla.org/en/docs/nsIDownloadProgressListener#onLocationChange.28.29
  21185.     onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {},
  21186.     
  21187.     onSecurityChange: function (aWebProgress, aRequest, aState) {},
  21188.     
  21189.     // required only for tabbrowser?
  21190.     onLinkIconAvailable: function (aBrowser, aHref) {},
  21191.     
  21192.     // required only for tabbrowser?
  21193.     // also: http://developer.mozilla.org/en/docs/nsIDownloadProgressListener#onLocationChange.28.29
  21194.     onLocationChange: function (aWebProgress, aRequest, aLocation) {}
  21195. }
  21196.  
  21197. var su_downloadProgressListener = 
  21198. {
  21199.     QueryInterface : function (iid)
  21200.     {
  21201.         if (!iid.equals(Components.interfaces.nsIWebProgressListener) &&
  21202.             !iid.equals(Components.interfaces.nsISupportsWeakReference) && // not implemented
  21203.             !iid.equals(Components.interfaces.nsISupports))
  21204.         {
  21205.             throw Components.errors.NS_ERROR_NO_INTERFACE;
  21206.         }
  21207.  
  21208.         return this;
  21209.     },
  21210.  
  21211.     onLocationChange : function(aWebProgress, aRequest, aLocation)
  21212.     {
  21213.         // Supposedly removed in ff3, but it's still being called by
  21214.         // ff3 tabbrowser.
  21215.         // 
  21216.         // See:
  21217.         // http://developer.mozilla.org/en/docs/nsIDownloadProgressListener#onLocationChange.28.29
  21218.         var domWindow = aWebProgress.DOMWindow;
  21219.     
  21220.         // Update urlbar only if a new page was loaded on the primary content area
  21221.         // this helps us weed out frames loading...
  21222.         if (domWindow == domWindow.top && aLocation != null) 
  21223.             su_refresh_pagemeta(false, 1);
  21224.     },
  21225.     
  21226.     onProgressChange : function (aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {},
  21227.     
  21228.     onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus)
  21229.     {
  21230.         const nsIWPL = Components.interfaces.nsIWebProgressListener;
  21231.         
  21232.         // do a try, we don't want to mess with state change...
  21233.         try {
  21234.             if (stumbleid == 0)
  21235.                 return;
  21236.             
  21237.             if (aWebProgress.DOMWindow != aWebProgress.DOMWindow.top)
  21238.                 return;
  21239.         } catch (e) { return; }
  21240.         
  21241.         if ((aStateFlags & nsIWPL.STATE_START) && (aStateFlags & nsIWPL.STATE_IS_REQUEST))
  21242.         {
  21243.             try {
  21244.                 su_prefetcher.pause();
  21245.             } catch (e) { su_log_error("PREFETCHER 2", e); }
  21246.             
  21247.             try {
  21248.                 aRequest.QueryInterface(Components.interfaces.nsIChannel);
  21249.             }
  21250.             catch (e) { return; }
  21251.             
  21252.             var redirect_url = aRequest.URI.asciiSpec;
  21253.             var original_url = aRequest.originalURI.asciiSpec;
  21254.             
  21255.             if (original_url == stumbled_url)
  21256.                 su_redirect_url = redirect_url;
  21257.                         
  21258.             // make sure url is beginning of request!!!!
  21259.             if (original_url.indexOf(su_base_url + "stumble/") == 0)
  21260.             {
  21261.                 // pull out the tag...
  21262.                 var spliturl = original_url.split("/");
  21263.                 if (spliturl.length >= 5)
  21264.                 {
  21265.                     var tag = spliturl[4];
  21266.                     var new_url = su_get_browser_url(null, true);
  21267.                     
  21268.                     // make sure new_url is "http://www.stumbleupon.com/explore.php"
  21269.                     if (new_url.indexOf(su_base_url + "explore.php") == 0)
  21270.                     {
  21271.                         aRequest.cancel(0);
  21272.                                         
  21273.                         su_unfocus_searchbox(); 
  21274.                         
  21275.                         var searchtag = (su_ds.isThruDomain(tag)) ? "" : tag;
  21276.  
  21277.                         // put it in the box
  21278.                         su_get_element("su_searchbox").value = searchtag;
  21279.                         su_get_element("su_searchbox").removeAttribute("mode");
  21280.                         su_old_search = searchtag;
  21281.                         su_last_typed_tag = 0;
  21282.                         su_visited_searchbox = 1;
  21283.  
  21284.                         // select and do it
  21285.                         setTimeout(su_select_topic, 100, "TAG_" + tag, tag, false);
  21286.                     }
  21287.                 }
  21288.             }
  21289.             else if (original_url.indexOf(su_base_url + "through.php?") == 0)
  21290.             {
  21291.                 aRequest.cancel(0);
  21292.             }
  21293.         }
  21294.         else if ((aStateFlags & nsIWPL.STATE_STOP) && (su_stumble_action_count > 0))
  21295.         {
  21296. // Note: The following causes execution to stop without throwing an
  21297. // error (ref: FF3, linux): 
  21298. //                if (aWebProgress)
  21299. //                    aWebProgress.su_loaded = true;
  21300.             try {
  21301.                 if (su_ds.getValue("$prefetch")    )
  21302.                     su_prefetcher.start();
  21303.             } catch (e) { su_log_error("PREFETCHER 3", e); }
  21304.         }
  21305.  
  21306.         
  21307.     },
  21308.  
  21309.     onLinkIconAvailable : function(aBrowser, aHref)
  21310.     {},
  21311.  
  21312.     onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
  21313.     {
  21314.         try {
  21315.             // Removed in ff3  See:
  21316.             // http://developer.mozilla.org/en/docs/nsIDownloadProgressListener#onStatusChange.28.29        if (aRequest)
  21317.             aRequest.QueryInterface(Components.interfaces.nsIChannel);
  21318.             var original_url = aRequest.originalURI.asciiSpec;
  21319.             
  21320.             // auto-stumble, done in click
  21321.             if (original_url.indexOf(su_base_url + "through.php?") != 0)
  21322.                 aRequest.cancel(0);
  21323.         } catch (e) {}
  21324.     },
  21325.  
  21326.     onSecurityChange : function(aWebProgress, aRequest, aState)
  21327.     {}
  21328. };
  21329.  
  21330. var su_http_observer = 
  21331. {
  21332.     // This is the observerService's observe listener.
  21333.     observe: function(aSubject, aTopic, aData) 
  21334.     {
  21335.         if (aTopic == 'http-on-modify-request') 
  21336.         {
  21337.             //!!! sometimes we get "Components is not defined" here? (why?)
  21338.             if (typeof(Components) != "undefined")
  21339.             {
  21340.                 aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
  21341.                 this.onModifyRequest(aSubject);
  21342.             }
  21343.         } 
  21344.         else if (aTopic == 'http-on-examine-response') 
  21345.         {
  21346.             //!!! sometimes we get "Components is not defined" here? (why?)
  21347.             if (typeof(Components) != "undefined")
  21348.             {
  21349.                 aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
  21350.                 this.onExamineResponse(aSubject);
  21351.             }
  21352.         }
  21353.     },
  21354.  
  21355.     onModifyRequest : function (oHttp)
  21356.     {
  21357.         var has_version = false;
  21358.         if (su_is_server_page(oHttp.URI.asciiSpec, ""))
  21359.         {
  21360.             has_version = true;
  21361.             oHttp.setRequestHeader("X-SU-Version", su_useragent, 0);
  21362.             if(stumbleid == 0)
  21363.             {
  21364.                 var first = su_ds.getValue("@first_version");
  21365.                 if(first != "")
  21366.                 {
  21367.                     first += " " + su_ds.getValue("@first_run_time");
  21368.                     oHttp.setRequestHeader("X-SU-First", first, 0);
  21369.                 }
  21370.                 var nowUtc = su_get_time_s();
  21371.                 oHttp.setRequestHeader("X-SU-Client-Time", nowUtc, 0);
  21372.             }
  21373.         }
  21374.  
  21375.         if (! su_is_auth_allowed(oHttp.URI.asciiSpec))
  21376.             return;
  21377.     
  21378.         // send authentication headers
  21379.         if (stumbleid == 0)
  21380.         {
  21381.             if (su_host && su_host.dist)
  21382.             {
  21383.                 if (! has_version)
  21384.                     oHttp.setRequestHeader("X-SU-Version", su_useragent, 0);
  21385.                 oHttp.setRequestHeader('X-SU-Dist', su_host.dist, 0);
  21386.             }
  21387.             return;
  21388.         }
  21389.         
  21390.         var url = oHttp.URI.asciiSpec;
  21391.         var sldetail = su_ds.getValue("#sldetail");
  21392.         if (sldetail && (url == sldetail.target))
  21393.         {
  21394.             oHttp.setRequestHeader('X-SU-Sldomain', sldetail.domain, 0);
  21395.             oHttp.setRequestHeader('X-SU-Sltermcount', sldetail.term_count + "", 0);
  21396.             oHttp.setRequestHeader('X-SU-Slfirstpage', ((sldetail.is_first_page) ? 1 : 0) + "", 0);
  21397.             su_ds.setValue("#sldetail", null);
  21398.         }
  21399.         
  21400.         url = url.toLowerCase();
  21401.         
  21402.         // 0 = do not merge header with old headers, replace them
  21403.         oHttp.setRequestHeader('X-SU-Username', stumbleid, 0);
  21404.         oHttp.setRequestHeader('X-SU-Password', stumblepass, 0);
  21405.         if (! has_version)
  21406.             oHttp.setRequestHeader("X-SU-Version", su_useragent, 0);
  21407.         if (su_host && su_host.dist)
  21408.             oHttp.setRequestHeader('X-SU-Dist', su_host.dist, 0);
  21409.         
  21410.         if (url.indexOf(su_serverhttp + "find_friends.php") != -1)
  21411.         {
  21412.             if (url.indexOf("pre3=") != -1)
  21413.             {
  21414.                 su_ds.setValue("#find_friends_optin", true);
  21415.                 su_ds.setValue("#find_friends_pre", "socialsearch");
  21416.             }
  21417.             else if (url.indexOf("pre=facebook") != -1)
  21418.             {
  21419.                 su_ds.setValue("#find_friends_pre", "facebook");
  21420.             }
  21421.         }
  21422.         
  21423.         if (oHttp.requestMethod != "POST")
  21424.             return;
  21425.         
  21426.         if (url.indexOf(su_serverhttp + "thanks.php") == 0)
  21427.         {
  21428.             try {
  21429.                 var str = su_get_debug_header();
  21430.                 if (str)
  21431.                     oHttp.setRequestHeader("X-SU-Debug", str, 0);
  21432.             } catch (e) { su_log_error("DEBUG HEADER", e); }
  21433.             return;
  21434.         }
  21435.         
  21436.         var bug_groups = ["stumbleupon", "help", "bugs", "beta", "firefox", "ie" ];
  21437.         var i;
  21438.         for (i = 0; i < bug_groups.length; i++)
  21439.         {
  21440.             if (url.indexOf("http://" + bug_groups[i] + ".group." + 
  21441.                         su_servername + "/forum/") == 0)
  21442.             {
  21443.                 try {
  21444.                     var str = su_get_debug_header();
  21445.                     if (str)
  21446.                         oHttp.setRequestHeader("X-SU-Debug", str, 0);
  21447.                 } catch (e) { su_log_error("DEBUG HEADER", e); }
  21448.                 break;
  21449.             }
  21450.         }
  21451.     },
  21452.     
  21453.     onExamineResponse : function (oHttp)
  21454.     {
  21455.         if (stumbleid == 0)
  21456.             return;
  21457.         
  21458.         //!!! grab oHttp.loadFlags and look for LOAD_FLAGS_IS_REFRESH to grab meta refreshes?
  21459.         var redirect_url = oHttp.URI.asciiSpec;
  21460.         var original_url = oHttp.originalURI.asciiSpec;
  21461.         
  21462.         if (su_log_mimetype)
  21463.             su_log("mimetype", original_url, redirect_url, oHttp.contentType);
  21464.         
  21465. //        if (original_url == "http://media.tumblr.com/mlsyKxOF8fzc9kd1zQ37q9b8o1_500.jpg")
  21466. //            su_dd("response", stumbled_url, original_url, redirect_url);
  21467.         
  21468.         var status = oHttp.responseStatus;
  21469.         if (stumbled_url != "" && original_url == stumbled_url && original_url != redirect_url)
  21470.         {
  21471. //            su_dd("set", 1, originval_url, redirect_url);
  21472.             // we have a stumble that has redirected to another page
  21473.             // NOTE: this will fire once for each redirect in a chain of redirects
  21474.             stumbled_redirect = redirect_url;
  21475.             // su_dp("STUMBLE REDIRECT", "ORIGINAL" + stumbled_url, "REDIRECT " + stumbled_redirect, "STATUS " + status);
  21476.         }
  21477.         
  21478. //        if (original_url == "http://media.tumblr.com/mlsyKxOF8fzc9kd1zQ37q9b8o1_500.jpg")
  21479. //            su_dd("after", stumbled_url, original_url, redirect_url);
  21480.         
  21481.         if (!su_is_server_page(original_url, ""))
  21482.             return;
  21483.         
  21484.         if (status != 200)
  21485.             return;
  21486.         
  21487.         if ((original_url.indexOf(su_serverhttp + "user.php?friend=") == 0) ||
  21488.                     (original_url.indexOf(su_serverhttp + "user.php?removefriend=") == 0))
  21489.         {
  21490.             setTimeout(su_get_friends, 0);
  21491.         }
  21492.         else if (original_url.match(/^http:\/\/[^\/]*\/badge\/badge_controller\.php\?a=thumbupurl&u=([^&]+)/))
  21493.         {
  21494.             var badge_match = original_url.match(/^http:\/\/[^\/]*\/badge\/badge_controller\.php\?a=thumbupurl&u=([^&]+)/);            
  21495.             if (badge_match.length < 2)
  21496.                 return;
  21497.             var url = decodeURIComponent(badge_match[1]);
  21498.             
  21499.             var url_detail = su_ds.lookup("url:url_detail", url);
  21500.             if (url_detail)
  21501.             {
  21502.                 url_detail.rating = 1;
  21503.                 su_refresh_pagemeta(12);
  21504.             }
  21505.             su_rate_getmeta(url, true);
  21506.         }
  21507.     }
  21508. };
  21509.  
  21510. try {
  21511.     su_service = Components.classes["@stumbleupon.com/stumbleupon-service;1"].getService().wrappedJSObject;
  21512. }
  21513. catch (e) {
  21514.     // seamonkey kludge
  21515.     su_include("chrome://stumbleupon/content/stumbleuponService.js");
  21516.     su_service = new su_Service();
  21517. }
  21518.  
  21519. su_service.setAgentDesc(su_useragent);
  21520. su_service.setLogCommunicationEnabled(su_log_communication);
  21521.  
  21522. su_service.setLogResourceCFD(su_log_resource_cfd);
  21523. su_service.setMessageLogEnabled(su_enable_message_log);
  21524. su_service.setForceCampusDistEnabled(su_test_campus_dist);
  21525. su_service.setLogErrorDomain(su_servername);
  21526.  
  21527. su_ds = su_service.getDatastore();
  21528.     
  21529. su_host = su_service.getHostSpec(navigator);
  21530.  
  21531. su_stumbleReporter = su_service.getStumbleReporter();
  21532.  
  21533. su_enable_hashed_password = su_host.sha1;
  21534.  
  21535. // current_user was used as far back as 4/2004, and ids was used between that and the usage of id_list.
  21536. su_new_install =(!su_ds.isPrefDefined("@first_version") && !su_ds.isPrefDefined("@id_list") && !su_ds.isPrefDefined("@ids") &&
  21537.                  (!su_ds.isPrefDefined("@current_user") || (su_ds.getValue("@current_user") == "")));
  21538.  
  21539. var su_useragent = "mozbar " + mozbar_version + " xpi";
  21540.  
  21541. su_useragent += " " + su_private_label;
  21542. su_useragent += " " + su_source_label;
  21543.  
  21544. var su_verstring = escape(su_useragent);
  21545.  
  21546. if (su_new_install)
  21547. {
  21548.     var first_info = su_useragent;
  21549.     var utc = su_get_time_s();
  21550.     su_ds.setValue("@first_version", first_info);
  21551.     su_ds.setValue("@first_run_time", utc);
  21552.     su_ds.setValue("javascript.options.showInConsole", true);
  21553. //        su_ds.setValue("javascript.options.strict", true);
  21554. }
  21555.  
  21556. window.addEventListener("load", su_handle_window_load, false);
  21557. window.addEventListener("unload", su_handle_window_unload, false);
  21558.  
  21559. su_init_login(false, false);
  21560.  
  21561. su_login_initialized = true;
  21562.  
  21563. su_migrate_version();
  21564.  
  21565. try {
  21566.     su_prefetcher = new su_Prefetcher();
  21567. } catch (e) { su_log_error("INSTANTIATE PREFETCHER", e); }
  21568.  
  21569. var su_observer_service = su_get_service(
  21570.             "@mozilla.org/observer-service;1",
  21571.             "nsIObserverService");
  21572.  
  21573. // We should move the http and em-action-requested observers into
  21574. // stumbleuponService.js after the FF3 release. -- JW
  21575.  
  21576. // Register the request and response observer.
  21577. su_observer_service.addObserver(su_http_observer, "http-on-modify-request", false);
  21578. su_observer_service.addObserver(su_http_observer, "http-on-examine-response", false);
  21579.  
  21580. // Register the host observer.
  21581. su_observer_service.addObserver(su_host_observer, "em-action-requested", false);
  21582.  
  21583. // Register the global event observer.
  21584. su_observer_service.addObserver(su_event_observer, "su_login", false);
  21585. su_observer_service.addObserver(su_event_observer, "su_logout", false);
  21586. su_observer_service.addObserver(su_event_observer, "su_change-password", false);
  21587. su_observer_service.addObserver(su_event_observer, "su_configure-toolbar", false);
  21588. su_observer_service.addObserver(su_event_observer, "su_referral-menu-dirty", false);
  21589. su_observer_service.addObserver(su_event_observer, "su_update-referral-menu", false);
  21590. su_observer_service.addObserver(su_event_observer, "su_refresh-category-selector", false);
  21591. su_observer_service.addObserver(su_event_observer, "su_dyn-channels-dirty", false);
  21592. su_observer_service.addObserver(su_event_observer, "su_update-dyn-channels", false);
  21593. su_observer_service.addObserver(su_event_observer, "su_schedule-remove-data", false);
  21594. su_observer_service.addObserver(su_event_observer, "su_message-button-click", false);
  21595.  
  21596. // su_include extra.js
  21597. su_include("chrome://stumbleupon/content/extra.js");
  21598.  
  21599. // Enable sidebar (conversation bar) if needed
  21600. if (su_sidebar_enabled)
  21601.     su_include("chrome://stumbleupon/content/sidebar.js");
  21602.  
  21603.  
  21604.